﻿using ArtMath.AuxiliaryTool;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.Component.Annotation;
using ArtMath.Component.Circle;
using ArtMath.Component.ConicalSection;
using ArtMath.Component.CoordinateSystem;
using ArtMath.Component.Line;
using ArtMath.Component.Vector;
using ArtMath.Setting;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using ArtMath.Data;
using ArtMath.Component;
using ArtMath.Control;
using ArtMath.Resource;
using ArtMath.Component.Point;
using ArtMath.PointCollection;
using ArtMath.Flag;
using ArtMath.Component.Polygon;
using ArtMath.Component.Interface;
using ArtMath.Component.Manager;
using ArtMath.Window;
using ArtMath.Command;
using System.Drawing.Drawing2D;
using ArtMath.Animation;
using ArtMath.Component.Angle;
using ArtMath.CommonType;
using ArtMath.Parameter;

namespace ArtMath
{
    public partial class SketchPad
    {
        public int PointCount, StraightLineCount;
        public event Action<SketchPad> ViewPropertyMenuClick, PasteObject, RefreshMenuClick;
        public event Action<SketchPad, IEnumerable<object>> CopyObject;
        public event Action<SketchPad, IEnumerable<Base>> PasteStyle;
        public event Action<SketchPad, Base> CopyStyle;
        public event Action<SketchPad, AnimationBase> AnimationCreated;
        public event Action<SketchPad, BasicParameter> ParameterCreated;
        [NonSerialized]
        Dictionary<ICurve, string> oldCurveAccuracyExpression = new Dictionary<ICurve, string>();
        [NonSerialized]
        Point toolStrip_MouseDownLocation, toolStripInitialLocation;
        [NonSerialized]
        bool toolStripMoved;
        [NonSerialized]
        List<ToolMenu> toolMenus;
        [NonSerialized]
        ToolButton[] toolButtons;
        [NonSerialized]
        bool inCanvas;
        class ToolMenu : ToolStripMenuItem
        {
            public Image LargeIcon { get; set; }
            public Image SmallIcon { get; }
            public ToolTypeName ToolType { get; set; }
            public bool RaiseCheckedChangedEvent { get; set; } = true;
            public ToolMenu(string text, Image img) : base(text, img)
            {
                SmallIcon = img;
            }
        }
        class ToolButton : ToolStripButton
        {
            public ToolTypeName ToolType { get; set; }
            public bool RaiseCheckedChangedEvent { get; set; } = true;
            public ToolButton(string text, Image img) : base(text, img)
            {
                CheckOnClick = true;
            }
        }
        void BuildFullScreen()
        {
            Form frm = new Form()
            {
                Text = $"{Name} [{Document.Title}] - {Flags.SoftwareName}{Flags.AdministratorFlag}",
                FormBorderStyle = FormBorderStyle.None,
                WindowState = FormWindowState.Maximized,
                MaximizeBox = false,
                ShowInTaskbar = false,
                MinimizeBox = false,
                ShowIcon = false,
                TopMost = true,
            };
            ToolStrip ts = new ToolStrip()
            {
                Dock = DockStyle.None,
            };
            frm.KeyDown += (object sender, KeyEventArgs e) =>
            {
                if (e.Shift)
                {
                    if (SelectedToolType == ToolTypeName.sf)
                    {
                        Canvas.Cursor = new Cursor(Resource.Properties.Resources.zoom_out.GetHicon());
                    }
                }
                switch (e.KeyCode)
                {
                    case Keys.Escape:
                        FullScreenMode = false;
                        break;
                    case Keys.F12:
                        ts.Visible = !ts.Visible;
                        break;
                }
            };
            frm.KeyUp += (object sender, KeyEventArgs e) =>
            {
                switch (e.KeyCode)
                {
                    case Keys.ShiftKey:
                        if (SelectedToolType == ToolTypeName.sf)
                        {
                            Canvas.Cursor = new Cursor(Resource.Properties.Resources.zoom_in.GetHicon());
                        }
                        break;
                }
            };
            frm.Controls.Add(Canvas);
            ToolButton ballpen, highlighter, movepad, moveobj, shift, zoom;
            ToolStripDropDownButton tools, erasers;
            ts.Items.AddRange(new ToolStripItem[]
            {
                new ToolStripButton(Resources.Translate("ExitFullScreen"),
                Resource.Properties.Resources.fullscreen_exit_32x, (object sender, EventArgs e) =>
                {
                    if (toolStripMoved) return;
                    FullScreenMode = false;
                }),
                new ToolStripSeparator(),
                tools = new ToolStripDropDownButton(Resources.Translate("ToolBox"), Resource.Properties.Resources.toolbox_32x),
                ballpen = new ToolButton(Resources.Translate("Ballpen"), Resource.Properties.Resources.ballpen_32x) { ToolType= ToolTypeName.yzb },
                highlighter = new ToolButton(Resources.Translate("Highlighter"), Resource.Properties.Resources.highlighter_32x) { ToolType= ToolTypeName.ygb },
                erasers = new ToolStripDropDownButton(Resources.Translate("Eraser"), Resource.Properties.Resources.eraser_32x),
                new ToolStripSeparator(),
                movepad = new ToolButton(Resources.JoinLocalizedString("Move", "Sketchpad"), Resource.Properties.Resources.cursor_hand_32x) { ToolType = ToolTypeName.ydhb },
                moveobj = new ToolButton(Resources.JoinLocalizedString("Move", "Object"), Resource.Properties.Resources.moveobj) { ToolType = ToolTypeName.yddx },
                shift = new ToolButton(Resources.Translate("SwitchPointType"), Resource.Properties.Resources.switchpoint_32x) { ToolType = ToolTypeName.qhdlx },
                new ToolStripSeparator(),
                new ToolStripButton(Resources.Translate("ZoomIn"),
                Resource.Properties.Resources.zoom_in_32x, (object sender, EventArgs e) =>
                {
                    if (toolStripMoved) return;
                    ZoomIn(Settings.Instance.ZoomDelta);
                }),
                new ToolStripButton(Resources.Translate("ZoomOut"),
                Resource.Properties.Resources.zoom_out_32x, (object sender, EventArgs e) =>
                {
                    if (toolStripMoved) return;
                    ZoomOut(Settings.Instance.ZoomDelta);
                }),
                zoom = new ToolButton(Resources.Translate("Zoom"), Resource.Properties.Resources.freezoom_32x) { ToolType = ToolTypeName.sf },
            });
            toolButtons = new ToolButton[] { ballpen, highlighter, movepad, moveobj, shift, zoom };
            foreach (ToolButton item in toolButtons)
            {
                item.CheckedChanged += ToolButton_CheckedChanged;
            }
            //工具分组菜单文本
            string[] headers = new string[] { Resources.Translate("Points"), Resources.JoinLocalizedString("Constructed", "Points"),
                Resources.JoinLocalizedString("Constructed", "Functions"),
                Resources.Translate("Lines"), Resources.JoinLocalizedString("Constructed", "Lines"),
                Resources.Translate("Vectors"), Resources.JoinLocalizedString("Constructed", "Vectors"), Resources.Translate("Polygons"),
                Resources.Translate("Circles_Arcs_Sectors"), Resources.JoinLocalizedString("Constructed", "Circles"),
                Resources.Translate("Conics"), Resources.Translate("Calculations")
            };
            //所有工具名
            string[] members = new string[]
            {
                //点
                Resources.Translate("FreePoint"), Resources.Translate("CoordinatePoint"),
                null,
                //构造点
                Resources.Translate("MidPoint"),
                Resources.Translate("CrossoverPoint"), Resources.JoinLocalizedString("Shape", "Center"),
                Resources.JoinLocalizedString("Polygon", "BaryCenter"),
                Resources.JoinLocalizedString("Triangle", "CircumCenter"),
                Resources.JoinLocalizedString("Triangle", "InCenter"),
                Resources.JoinLocalizedString("Triangle", "OrthoCenter"),
                null,
                //构造函数
                Resources.Translate("DerivedFunction"),//只生成一阶
                null,
                //线
                Resources.Translate(nameof(TwoPointsLineSegment)),
                Resources.Translate(nameof(TwoPointsRay)),
                Resources.Translate(nameof(TwoPointsStraightLine)),
                null,
                //构造线
                Resources.Translate(nameof(ParallelLine)), Resources.Translate(nameof(VerticalLine)),
                Resources.Translate(nameof(PerpendicularBisector)), Resources.Translate(nameof(VerticalLineSegment)),
                Resources.Translate(nameof(TangentLine)),
                Resources.Translate(nameof(AngleBisector)),
                null,
                //向量
                Resources.Translate(nameof(TwoPointsVector)),
                null,
                //构造向量
                Resources.Translate(nameof(TwoVectorsAddition)),
                Resources.Translate(nameof(TwoVectorsSubtraction)), Resources.Translate(nameof(ParallelVector)),
                Resources.Translate(nameof(VerticalVector)),
                null,
                //多边形
                Resources.Translate(nameof(ArbitraryPolygon)),
                Resources.Translate(nameof(RightTriangle)), Resources.Translate(nameof(IsoscelesTriangle)),
                Resources.Translate(nameof(IsoscelesRightTriangle)), Resources.Translate(nameof(EquilateralTriangle)),
                Resources.Translate(nameof(Parallelogram)), Resources.Translate(nameof(Component.Polygon.Rectangle)),
                Resources.Translate(nameof(Diamond)), Resources.Translate(nameof(Square)), Resources.Translate(nameof(Trapezoid)),
                Resources.Translate(nameof(IsoscelesTrapezoid)), Resources.Translate(nameof(RightAngledTrapezoid)),
                null,
                //圆（弧）、扇形
                Resources.Translate(nameof(CenterPointCircle)), Resources.Translate(nameof(DiameterCircle)),
                Resources.Translate(nameof(ThreePointsCircle)), Resources.Translate(nameof(ThreePointsArc)),
                Resources.Translate(nameof(ThreePointsSector)),
                Resources.Translate(nameof(ThreePointsArch)),
                null,
                //构造圆
                Resources.Translate(nameof(CircumCircle)), Resources.Translate(nameof(InscribedCircle)),
                null,
                //圆锥曲线
                Resources.Translate(nameof(LongShortAxisEllipse)), Resources.Translate(nameof(FocusPointEllipse)),
                Resources.Translate(nameof(FocusDirectrixEllipse)),
                Resources.Translate(nameof(RealImaginaryAxisHyperbola)),
                Resources.Translate(nameof(FocusPointHyperbola)), Resources.Translate(nameof(FocusImaginaryAxisHyperbola)),
                Resources.Translate(nameof(FocusDirectrixHyperbola)),
                Resources.Translate(nameof(FocusDirectrixParabola)),
                null,
                //计算
                Resources.Translate("TwoPointsDistance"),
                Resources.Translate("PointStraightLineDistance"), Resources.Translate("TwoParallelLinesDistance"),
                Resources.Translate("TwoStraightLinesIncludedAngle"),
                Resources.Translate("ThreePointsAngle"),
                Resources.Translate("TwoVectorsScalarProduct"), Resources.Translate("TwoVectorsCrossProduct"),
            };
            //所有工具类型
            ToolTypeName[] types = new ToolTypeName[]
            {
                //点
                ToolTypeName.zyd, ToolTypeName.zbd,
                ToolTypeName.Unknown,
                //构造点
                ToolTypeName.zd, ToolTypeName.jd, ToolTypeName.zx, ToolTypeName.dbxzx, ToolTypeName.sjxwx, ToolTypeName.sjxnx, ToolTypeName.sjxcx,
                ToolTypeName.Unknown,
                //构造函数
                ToolTypeName.dhs,
                ToolTypeName.Unknown,
                //线
                ToolTypeName.ldxd, ToolTypeName.ldsx, ToolTypeName.ldzx,
                ToolTypeName.Unknown,
                //构造线
                ToolTypeName.pxx, ToolTypeName.cx, ToolTypeName.zcx, ToolTypeName.cxd, ToolTypeName.qx, ToolTypeName.jpfx,
                ToolTypeName.Unknown,
                //向量
                ToolTypeName.ldxl,
                ToolTypeName.Unknown,
                //构造向量,
                ToolTypeName.xljf, ToolTypeName.xljf_, ToolTypeName.pxxl, ToolTypeName.czxl,
                ToolTypeName.Unknown,
                //多边形
                ToolTypeName.rydbx, ToolTypeName.zjsjx, ToolTypeName.dysjx, ToolTypeName.dyzjsjx, ToolTypeName.dbsjx,
                ToolTypeName.pxsbx, ToolTypeName.jx, ToolTypeName.lx, ToolTypeName.zfx, ToolTypeName.tx, ToolTypeName.dytx, ToolTypeName.zjtx,
                ToolTypeName.Unknown,
                //圆（弧）、扇形
                ToolTypeName.yxddy, ToolTypeName.zjy, ToolTypeName.sdy, ToolTypeName.sdyh, ToolTypeName.sdsx, ToolTypeName.sdgx,
                ToolTypeName.Unknown,
                //构造圆
                ToolTypeName.wjy, ToolTypeName.nqy,
                ToolTypeName.Unknown,
                //圆锥曲线
                ToolTypeName.cdzty, ToolTypeName.jdddty, ToolTypeName.jdzxty, ToolTypeName.sxzsqx, ToolTypeName.jdddsqx,
                ToolTypeName.jdxzsqx, ToolTypeName.jdzxsqx, ToolTypeName.jdzxpwx,
                ToolTypeName.Unknown,
                //计算
                ToolTypeName.ldjl, ToolTypeName.ddzxdjl, ToolTypeName.lzxjl, ToolTypeName.lzxjj, ToolTypeName.sdjd, ToolTypeName.lxldslj, ToolTypeName.lxldxlj
            };
            //所有小图标和部分大图标
            Image[] toolSmallIcons = new Image[]
            {
                //点
                ToolIcons_Small.new_point_16x,
                CoordinateType == CoordinateSystemType.PolarCoordinate ? ToolIcons_Small.zbd2_16x : ToolIcons_Small.zbd_16x,
                null,
                //构造点
                ToolIcons_Small.zd_16x, ToolIcons_Small.jd_16x, ToolIcons_Small.zdbxzx_16x, ToolIcons_Small.zhongxin_16x,
                ToolIcons_Small.wx_16x, ToolIcons_Small.sjxnx_16x, ToolIcons_Small.chuixin_16x,
                null,
                //构造函数
                ToolIcons_Small.dhs_16x,
                null,
                //线
                ToolIcons_Small.ldxd_16x, ToolIcons_Small.ldsx_16x, ToolIcons_Small.ldzx_16x,
                null,
                //构造线
                ToolIcons_Small.pxx_16x, ToolIcons_Small.cx_16x, ToolIcons_Small.zcx_16x, ToolIcons_Small.cxd_16x,
                ToolIcons_Small.qxqx_16x, ToolIcons_Small.jpfx_16x,
                null,
                //向量
                ToolIcons_Small.vector_16x,
                null,
                //构造向量
                ToolIcons_Small.xljf_16x, ToolIcons_Small.xljf__16x, ToolIcons_Small.pxxl_16x, ToolIcons_Small.czxl_16x,
                null,
                //多边形
                ToolIcons_Small.polygon_16x, ToolIcons_Small.zjsjx_16x, ToolIcons_Small.dysjx_16x, ToolIcons_Small.dyzjsjx_16x,
                ToolIcons_Small.dbsjx_16x, ToolIcons_Small.pxsbx_16x, ToolIcons_Small.rectangle_16x, ToolIcons_Small.diamond_16x,
                ToolIcons_Small.square_16x, ToolIcons_Small.tx_16x, ToolIcons_Small.dytx_16x, ToolIcons_Small.zjtx_16x,
                null,
                //圆（弧）、扇形
                ToolIcons_Small.yxysyd_16x, ToolIcons_Small.zjy_16x, ToolIcons_Small.sdy_16x, ToolIcons_Small.sdh_16x,
                ToolIcons_Small.sdsx_16x, ToolIcons_Small.sdgx_16x,
                null,
                //构造圆
                ToolIcons_Small.wjy_16x, ToolIcons_Small.nqy_16x,
                null,
                //圆锥曲线
                ToolIcons_Small.dczdzty_16x, ToolIcons_Small.jdddty_16x, ToolIcons_Small.jdzxty_16x, ToolIcons_Small.szxzsqx_16x,
                ToolIcons_Small.jdydsqx_16x, ToolIcons_Small.jdxzsqx_16x, ToolIcons_Small.jdzxsqx_16x, ToolIcons_Small.jdzxpwx_16x,
                null,
                //计算
                ToolIcons_Small.distance_16x, ToolIcons_Small.dxjl_16x, ToolIcons_Small.lzxjl_16x, ToolIcons_Small.lzxjj_16x,
                ToolIcons_Small.sdjd_16x, ToolIcons_Small.lxlslj_16x, ToolIcons_Small.lxlxlj_16x,
            }, toolLargeIcons = new Image[]
            {
                //点
                ToolIcons_Large.new_point_32x,
                CoordinateType == CoordinateSystemType.PolarCoordinate ? ToolIcons_Large.zbd2_32x : ToolIcons_Large.zbd_32x,
                null,
                null,null,null,null,null,null,null,
                null,
                null,
                null,
                //线
                ToolIcons_Large.ldxd_32x, ToolIcons_Large.ldsx_32x, ToolIcons_Large.ldzx_32x,
                null,
                null,null,null,null,null,null,
                null,
                //向量
                ToolIcons_Large.vector_32x,
                null,
                null,null,null,null,
                null,
                //多边形
                ToolIcons_Large.polygon_32x, ToolIcons_Large.zjsjx_32x, ToolIcons_Large.dysjx_32x, ToolIcons_Large.dyzjsjx_32x,
                ToolIcons_Large.dbsjx_32x, ToolIcons_Large.pxsbx_32x, ToolIcons_Large.rectangle_32x, ToolIcons_Large.diamond_32x,
                ToolIcons_Large.square_32x, ToolIcons_Large.tx_32x, ToolIcons_Large.dytx_32x, ToolIcons_Large.zjtx_32x,
                null,
                //圆（弧）、扇形
                ToolIcons_Large.yxysyd_32x, ToolIcons_Large.zjy_32x, ToolIcons_Large.sdy_32x, ToolIcons_Large.sdh_32x,
                ToolIcons_Large.sdsx_32x, ToolIcons_Large.sdgx_32x,
                null,
                null,null,
                null,
                //圆锥曲线
                ToolIcons_Large.dczdzty_32x, ToolIcons_Large.jdddty_32x, ToolIcons_Large.jdzxty_32x, ToolIcons_Large.szxzsqx_32x,
                ToolIcons_Large.jdydsqx_32x, ToolIcons_Large.jdxzsqx_32x, ToolIcons_Large.jdzxsqx_32x, ToolIcons_Large.jdzxpwx_32x,
                null,
                null,null,null,null,null,null,null,
            };
            int index = -1;
            toolMenus = new List<ToolMenu>();
            ToolMenu memberItem;
            for (int i = 0; i < headers.Length; i++)
            {
                ToolStripMenuItem groupItem = new ToolStripMenuItem(headers[i]);
                tools.DropDownItems.Add(groupItem);
                while (++index < members.Length && members[index] != null)
                {
                    memberItem = new ToolMenu(members[index], toolSmallIcons[index])
                    {
                        LargeIcon = toolLargeIcons[index],
                        ToolType = types[index],
                    };
                    groupItem.DropDownItems.Add(memberItem);
                    switch (i)
                    {
                        case 0:
                        case 3:
                        case 5:
                        case 7:
                        case 8:
                        case 10:
                            memberItem.CheckOnClick = true;
                            memberItem.CheckedChanged += ToolMenu_CheckedChanged;
                            toolMenus.Add(memberItem);
                            break;
                        default:
                            memberItem.Click += OnceToolMenu_Click;
                            break;
                    }
                }
            }
            tools.InsertShortcutKey();//添加快捷键字符
            memberItem = new ToolMenu(Resources.Translate("PointEraser"), ToolIcons_Small.pointeraser_16x)
            {
                LargeIcon = ToolIcons_Large.pointeraser_32x,
                ToolType = ToolTypeName.dxp,
                CheckOnClick = true,
            };
            memberItem.CheckedChanged += ToolMenu_CheckedChanged;
            toolMenus.Add(memberItem);
            erasers.DropDownItems.Add(memberItem);
            memberItem = new ToolMenu(Resources.Translate("RegionEraser"), ToolIcons_Small.qyxp_16x)
            {
                LargeIcon = ToolIcons_Large.qyxp_32x,
                ToolType = ToolTypeName.qyxp,
                CheckOnClick = true,
            };
            memberItem.CheckedChanged += ToolMenu_CheckedChanged;
            toolMenus.Add(memberItem);
            erasers.DropDownItems.Add(memberItem);
            erasers.InsertShortcutKey();
            ts.MouseMove += (object sender, System.Windows.Forms.MouseEventArgs e) =>
            {
                if (e.Button == MouseButtons.Left)
                {
                    Point current = ts.PointToScreen(e.Location);
                    ts.Location = new Point(toolStripInitialLocation.X + current.X - toolStrip_MouseDownLocation.X,
                        toolStripInitialLocation.Y + current.Y - toolStrip_MouseDownLocation.Y);
                    toolStripMoved = true;
                }
            };
            foreach (ToolStripItem item in ts.Items)
            {
                item.ImageScaling = ToolStripItemImageScaling.None;
                item.DisplayStyle = ToolStripItemDisplayStyle.Image;
                item.MouseDown += ToolStripItem_MouseDown;
                item.MouseMove += ToolStripItem_MouseMove;
            }
            ToolStripCreated?.Invoke(this, ts);
            frm.Controls.Add(ts);
            ts.BringToFront();
            frm.Show();
            ts.Location = new Point((ts.Parent.ClientSize.Width - ts.Width) >> 1, ts.Parent.ClientSize.Height - ts.Height);
        }
        void ToolButton_CheckedChanged(object sender, EventArgs e)
        {
            ToolButton btn = sender as ToolButton;
            if (!btn.RaiseCheckedChangedEvent) return;
            if (btn.Checked)
            {
                SelectedToolType = btn.ToolType;
                //取消选中其他工具
                foreach (ToolButton item in toolButtons)
                {
                    if (ReferenceEquals(item, btn)) continue;
                    if (item.Checked)
                    {
                        item.RaiseCheckedChangedEvent = false;
                        item.Checked = false;
                        item.RaiseCheckedChangedEvent = true;
                        return;
                    }
                }
                foreach (ToolMenu item in toolMenus)
                {
                    if (item.Checked)
                    {
                        item.RaiseCheckedChangedEvent = false;
                        item.Checked = false;
                        item.RaiseCheckedChangedEvent = true;
                        return;
                    }
                }
            }
            else
            {
                SelectedToolType = ToolTypeName.zz;
            }
        }
        void OnceToolMenu_Click(object sender, EventArgs e)
        {
            ToolMenu menu = sender as ToolMenu;
            SelectedToolType = menu.ToolType;
            BuildOnce();
        }
        void ToolMenu_CheckedChanged(object sender, EventArgs e)
        {
            ToolMenu menu = sender as ToolMenu;
            if (!menu.RaiseCheckedChangedEvent) return;
            ToolStripItem owner = menu;
            while (owner.OwnerItem != null)
            {
                owner = owner.OwnerItem;
            }
            if (menu.Checked)
            {
                owner.Image = menu.LargeIcon;
                SelectedToolType = menu.ToolType;
                //取消选中其他工具
                foreach (ToolMenu item in toolMenus)
                {
                    if (ReferenceEquals(item, menu)) continue;
                    if (item.Checked)
                    {
                        item.RaiseCheckedChangedEvent = false;
                        item.Checked = false;
                        item.RaiseCheckedChangedEvent = true;
                        return;
                    }
                }
                foreach (ToolButton item in toolButtons)
                {
                    if (item.Checked)
                    {
                        item.RaiseCheckedChangedEvent = false;
                        item.Checked = false;
                        item.RaiseCheckedChangedEvent = true;
                        return;
                    }
                }
            }
            else
            {
                owner.Image = Resource.Properties.Resources.toolbox_32x;
                SelectedToolType = ToolTypeName.zz;
            }
        }
        void ToolStripItem_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ToolStripItem item = sender as ToolStripItem;
                toolStrip_MouseDownLocation = item.Owner.PointToScreen(e.Location);
                toolStripInitialLocation = item.Owner.Location;
            }
            toolStripMoved = false;
        }
        void ToolStripItem_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ToolStripItem item = sender as ToolStripItem;
                Point current = item.Owner.PointToScreen(e.Location);
                item.Owner.Location = new Point(toolStripInitialLocation.X + current.X - toolStrip_MouseDownLocation.X,
                    toolStripInitialLocation.Y + current.Y - toolStrip_MouseDownLocation.Y);
                toolStripMoved = true;
            }
        }
        public class CanvasBox : PictureBox
        {
            public CanvasBox()
            {
                DoubleBuffered = true;
                BackColor = Color.White;
                BackgroundImageLayout = ImageLayout.None;
                Dock = DockStyle.Fill;
            }
        }
        void BuildTabPage()
        {
            tabPage = new TabPage()
            {
                BackColor = Color.FromArgb(201, 211, 226),
                AutoScroll = true,
                Tag = this,
            };
            topPanel = new Panel()
            {
                Dock = DockStyle.Top,
                BackColor = Color.LightGreen,
                Height = 30,
                Visible = false,
            };
            TabPage.Controls.Add(topPanel);
            msgLabel = new Label()
            {
                AutoSize = false,
                AutoEllipsis = true,
                TextAlign = ContentAlignment.MiddleLeft,
                Font = new Font("Microsoft YaHei", 10),
                ImageAlign = ContentAlignment.MiddleLeft,
                Dock = DockStyle.Fill,
            };
            topPanel.Controls.Add(msgLabel);
            msgClose = new PictureBox()
            {
                Dock = DockStyle.Right,
                Width = topPanel.Height,
                Image = Resource.Properties.Resources.btnClose,
                Cursor = Cursors.Hand,
                SizeMode = PictureBoxSizeMode.CenterImage,
            };
            msgClose.Click += (object sender, EventArgs e) =>
            {
                if (countDownThread != null && countDownThread.IsAlive)
                {
                    countDownThread.Abort();
                }
                topPanel.Hide();
            };
            topPanel.Controls.Add(msgClose);
            canvas = new CanvasBox();
            Canvas.Paint += (object sender, PaintEventArgs e) =>
            {
                Paint(e.Graphics);
            };
            Canvas.DoubleClick += Canvas_DoubleClick;
            Canvas.MouseMove += Canvas_MouseMove;
            Canvas.MouseDown += Canvas_MouseDown;
            Canvas.MouseUp += Canvas_MouseUp;
            Canvas.MouseWheel += Canvas_MouseWheel;
            Canvas.MouseLeave += Canvas_MouseLeave;
            Canvas.MouseEnter += Canvas_MouseEnter;
            Canvas.SizeChanged += (object sender, EventArgs e) =>
            {
                if (Canvas.Size.Width == 0 || Canvas.Size.Height == 0) return;
                if (Canvas.Dock == DockStyle.None)
                {
                    Canvas.Location = new Point((Canvas.Parent.ClientSize.Width - Canvas.Width) >> 1,
                        (Canvas.Parent.ClientSize.Height - Canvas.Height) >> 1);
                }
                if (oldSize.Width != 0 && oldSize.Height != 0)
                {
                    if (Coordinate != null)
                    {
                        Coordinate.OriginCoordinate.SetSeparately(Canvas.Width * Coordinate.OriginCoordinate.X.Value / oldSize.Width,
                            Canvas.Height * Coordinate.OriginCoordinate.Y.Value / oldSize.Height);
                    }
                }
                oldSize = Canvas.Size;
            };
            TabPage.Controls.Add(Canvas);
            Document.PageContainer.TabPages.Add(TabPage);
        }
        void Canvas_MouseEnter(object sender, EventArgs e)
        {
            inCanvas = true;
            switch (SelectedToolType)
            {
                case ToolTypeName.dxp:
                case ToolTypeName.qhdlx:
                case ToolTypeName.yddx:
                    OperateRing((Ring rng) => 
                    {
                        if (rng.Radius > 0)
                        {
                            Flags.CursorVisible = false;
                            rng.Visible = true;
                        }
                    });
                    break;
            }
        }
        void Canvas_MouseLeave(object sender, EventArgs e)
        {
            inCanvas = false;
            switch (SelectedToolType)
            {
                case ToolTypeName.dxp:
                case ToolTypeName.qhdlx:
                case ToolTypeName.yddx:
                    OperateRing((Ring rng) =>
                    {
                        if (rng.Radius > 0)
                        {
                            Flags.CursorVisible = true;
                            rng.Visible = false;
                        }
                    });
                    break;
            }
            if (Canvas.ContextMenuStrip == null || !Canvas.ContextMenuStrip.Visible)
            {
                ClearAbsorbedObjects();
                ClearAbsorbedPropertyDisplayers();
            }
            Canvas.Invalidate();
            CurrentCoordinateChanged?.Invoke(this, null);
        }
        void Canvas_DoubleClick(object sender, EventArgs e)
        {
            if (HostObj == null)
            {
                foreach (Base item in AbsorbedObjects)
                {
                    switch (item.ToolType)
                    {
                        case ToolTypeName.zyd:
                            if (SelectedToolType != ToolTypeName.qhdlx)
                            {
                                OldCoordinate = Coordinate;
                                (item as PointBase).ConvertType(ToolTypeName.zbd);
                                OldCoordinate = null;
                            }
                            break;
                        case ToolTypeName.zbd:
                            if (SelectedToolType != ToolTypeName.qhdlx)
                            {
                                OldCoordinate = Coordinate;
                                (item as PointBase).ConvertType(ToolTypeName.zyd);
                                OldCoordinate = null;
                            }
                            break;
                        case ToolTypeName.wb:
                            TextArea ta = item as TextArea;
                            TextBox tb = new TextBox()
                            {
                                ImeMode = ImeMode.NoControl,
                                Multiline = true,
                                Font = ta.TextFont,
                                BackColor = ta.BackgroundColor,
                                ForeColor = ta.TextColor,
                                ScrollBars = ScrollBars.Vertical,
                                Location = PxyToMouseLocation(ta.Pxy),
                                Size = Size.Ceiling(ta.ActualSize),
                                Text = ta.Text,
                                Tag = ta,
                            };
                            Canvas.Controls.Add(tb);
                            break;
                    }
                }
            }
            else
            {
                PenBase pb = HostObj as PenBase;
                if (pb != null)
                {
                    pb.Complete();
                }
                else
                {
                    ArbitraryPolygon ap = HostObj as ArbitraryPolygon;
                    if (ap != null)
                    {
                        ap.Complete();
                    }
                }
            }
        }
        void Canvas_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (Flags.Ctrl)
            {
                if (e.Delta > 0)
                {
                    ZoomIn(Settings.Instance.ZoomDelta);
                }
                else
                {
                    ZoomOut(Settings.Instance.ZoomDelta);
                }
            }
            else
            {
                if (Flags.Shift)
                {
                    Location.X.SetExpression(Location.X.Value - Math.Sign(e.Delta) * Settings.Instance.HorizontalScrollDistance);
                    foreach (System.Windows.Forms.Control item in Canvas.Controls)
                    {
                        item.Left -= (int)(Math.Sign(e.Delta) * Settings.Instance.HorizontalScrollDistance);
                    }
                }
                else
                {
                    Location.Y.SetExpression(Location.Y.Value + Math.Sign(e.Delta) * Settings.Instance.VerticalScrollDistance);
                    foreach (System.Windows.Forms.Control item in Canvas.Controls)
                    {
                        item.Top += (int)(Math.Sign(e.Delta) * Settings.Instance.VerticalScrollDistance);
                    }
                }
            }
            //if (e.Delta < 0)
            //{
            //    if (Program.Ctrl)
            //    {
            //        if (Program.Shift)
            //        {
            //            Canvas.Width -= e.Delta >> 1;
            //            //if ((Coordinate as clsRectangular_Coordinates) != null)
            //            //{
            //            //    (Coordinate as clsRectangular_Coordinates).originCo.X = (Coordinate as clsRectangular_Coordinates).getOriginCo().X;
            //            //}
            //            //if ((Coordinate as clsPolar_Coordinates) != null)
            //            //{
            //            //    frmMain.nowdoc.(Coordinate as clsRectangular_Coordinates).OriginCoX = frmMain.nowdoc.(Coordinate as clsRectangular_Coordinates).getRateX();
            //            //}
            //            TabPage.HorizontalScroll.Value = TabPage.HorizontalScroll.Maximum;
            //        }
            //        else
            //        {
            //            Canvas.Height -= e.Delta >> 1;
            //            //if ((Coordinate as clsRectangular_Coordinates) != null)
            //            //{
            //            //    (Coordinate as clsRectangular_Coordinates).originCo.Y = (Coordinate as clsRectangular_Coordinates).getOriginCo().Y;
            //            //}
            //            //if ((Coordinate as clsPolar_Coordinates) != null)
            //            //{
            //            //    frmMain.nowdoc.(Coordinate as clsRectangular_Coordinates).OriginCoX = frmMain.nowdoc.(Coordinate as clsRectangular_Coordinates).getRateX();
            //            //}
            //        }
            //        //pb.Location = new Point((plCtn.Width - pb.Width) >> 1, (plCtn.Height - pb.Height) >> 1);
            //        Canvas.Invalidate();
            //    }
            //}
            ////scrollBarLocation = new Point(tabPage.HorizontalScroll.Value, tabPage.VerticalScroll.Value);
        }
        void Canvas_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            NewMouseEventLocation = e.Location;
            NewPLocation = MouseLocationToPxy(e.Location);
            switch (e.Button)
            {
                case MouseButtons.Left:
                    switch (SelectedToolType)
                    {
                        case ToolTypeName.zz:
                            if (NewMouseEventLocation == mouseDownLocation && AbsorbedObjects.Count == 0)
                            {
                                SelectNothing();
                            }
                            break;
                        case ToolTypeName.sf:
                            //Program.WinMain.tscbScale.Text = scale.X.Value == scale.Y.Value ? (scale.X.Value * 100).ToString() + "%" : string.Empty;
                            break;
                        case ToolTypeName.ydhb:
                            Canvas.Cursor = new Cursor(Resource.Properties.Resources.cursor_hand.GetHicon());
                            ChangeCurveAccuracy(false);
                            break;
                        case ToolTypeName.yddx:
                            Canvas_MouseMove(sender, e);
                            //ChangeCurveAccuracy(false);
                            foreach (Base item in AbsorbedObjects)
                            {
                                if (item.Movable)
                                {
                                    ShapeBase sb = item as ShapeBase;
                                    if (sb != null)
                                    {
                                        MoveObject_DoMouseUp(sb);
                                    }
                                }
                            }
                            OperateRing((Ring rng) => { rng.Visible = true; });
                            //ShowCursor(0);
                            break;
                        //case ToolTypeName.qhdlx:
                        //    OperateRing((Ring rng) => { rng.Visible = true; });
                        //    break;
                        case ToolTypeName.zybh:
                            Canvas_MouseMove(sender, e);
                            break;
                        default:
                            if (TrackObj != null)
                            {
                                if (!(TrackObj is PenBase) && mouseDownLocation != NewMouseEventLocation)
                                {
                                    Canvas_MouseDown(sender, e);
                                }
                            }
                            break;
                    }
                    if (ToolObj != null && (ToolObj is RectangleDragger || ToolObj is RegionEraser))
                    {
                        ToolObj.Complete();
                        ToolObj = null;
                        Canvas.Invalidate();
                    }
                    break;
            }
            ToolObj?.MouseUp(new AuxiliaryTool.MouseEventArgs(NewPLocation, e.Button));
            OldMouseEventLocation = NewMouseEventLocation;
            OldPLocation = NewPLocation;
        }
        void Canvas_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            NewMouseEventLocation = e.Location;
            NewPLocation = MouseLocationToPxy(e.Location);
            CurrentCoordinateChanged?.Invoke(this, NewPLocation);
            bool cnb = false;
            switch (e.Button)
            {
                case MouseButtons.Left:
                    switch (SelectedToolType)
                    {
                        case ToolTypeName.ydhb:
                            translate.SetSeparately(translate.X.Value + e.X - OldMouseEventLocation.X,
                                translate.Y.Value + e.Y - OldMouseEventLocation.Y);
                            break;
                        case ToolTypeName.yddx:
                            if (AbsorbedObjects.Count == 0)
                            {
                                foreach (PropertyDisplayer item in AbsorbedPropertyDisplayers)
                                {
                                    item.Move(NewPLocation - OldPLocation);
                                }
                            }
                            else
                            {
                                foreach (Base item in AbsorbedObjects)
                                {
                                    if (item.Movable || item == Coordinate?.OriginPoint)
                                    {
                                        if (item is PointBase)
                                        {
                                            //注意：如果此处的目标位置是点的原位置加上鼠标的偏移量的话，固定到圆和固定到线的函数效果会不佳！
                                            MoveObject_DoMouseMove(item as ShapeBase, NewPLocation);
                                        }
                                        else if (item is ShapeBase)
                                        {
                                            MoveObject_DoMouseMove(item as ShapeBase, NewPLocation - OldPLocation);
                                        }
                                        else
                                        {
                                            item.Move(NewPLocation - OldPLocation);
                                        }
                                    }
                                }
                            }
                            break;
                        default:
                            cnb = true;
                            break;
                    }
                    Canvas.Invalidate();
                    break;
                case MouseButtons.None:
                    switch (SelectedToolType)
                    {
                        case ToolTypeName.yddx:
                            //OperateRing((Ring rng) => { rng.MouseMove(NewPLocation); });
                            CheckNearBy(NewPLocation, Layer.SelectedItems.Count > 0);
                            if (AbsorbedObjects.Count == 0)
                            {
                                PropertyDisplayersCheckNearBy(NewPLocation, Layer.SelectedItems.Count > 0);
                            }
                            Canvas.Cursor = AbsorbedObjects.Count > 0 || AbsorbedPropertyDisplayers.Count > 0 ? Cursors.SizeAll : Cursors.Default;
                            break;
                        case ToolTypeName.qhdlx:
                            //OperateRing((Ring rng) => { rng.MouseMove(NewPLocation); });
                            CheckNearBy(NewPLocation, false, true, (Base obj) =>
                            {
                                return obj is PointBase;
                            });
                            Canvas.Cursor = AbsorbedObjects.Count > 0 ? Cursors.Hand : Cursors.Default;
                            break;
                        default:
                            cnb = true;
                            break;
                    }
                    break;
            }
            if (cnb)
            {
                switch (SelectedToolType)
                {
                    case ToolTypeName.zz:
                        if (e.Button == MouseButtons.None)
                        {
                            CheckNearBy(NewPLocation, false, true);
                            Canvas.Cursor = AbsorbedObjects.Count > 0 ? Cursors.Hand : Cursors.Default;
                        }
                        break;
                    case ToolTypeName.jd:
                        CheckNearBy(NewPLocation, false, true, (Base obj) =>
                        {
                            return !(obj is PointBase);
                        });
                        break;
                    //case ToolTypeName.qx:
                    //    CheckNearBy(NewPLocation, false, false, (Base obj) =>
                    //    {
                    //        return obj is ICurveLike;
                    //    });
                    //    break;
                    case ToolTypeName.yzb:
                    case ToolTypeName.ygb:
                    case ToolTypeName.wb:
                    case ToolTypeName.tp:
                    case ToolTypeName.hs:
                    case ToolTypeName.csfc:
                    case ToolTypeName.sf:
                    case ToolTypeName.ydhb:
                    case ToolTypeName.dxp:
                    case ToolTypeName.qyxp:
                    case ToolTypeName.zybh:
                        break;
                    default:
                        CheckNearBy(NewPLocation, false, true, (Base obj) =>
                        {
                            return !(obj is CustomBase);
                        });
                        break;
                }
            }
            if (e.Button == MouseButtons.Left || !(TrackObj is PenBase))
            {
                HostTrackComponentBuilding(NewPLocation);
            }
            ToolObj?.MouseMove(new MouseMoveEventArgs(NewPLocation, e.Button, SizeD.FromPointD(NewPLocation - OldPLocation)));
            OldMouseEventLocation = NewMouseEventLocation;
            OldPLocation = NewPLocation;
        }
        public void BuildCalculatedParameter(ToolTypeName type)
        {
            CalculatedParameter cp;
            switch (type)
            {
                case ToolTypeName.lzxjj:
                    StraightLineBase[] sls = PickStraightLines(2);
                    if (sls != null)
                    {
                        for (int i = 0; i < sls.Length - 1; i++)
                        {
                            for (int j = i + 1; j < sls.Length; j++)
                            {
                                cp = new TwoStraightLinesIncludedAngleParameter(this, StdObjName("IncludedAngle"), sls[i], sls[j]);
                                cp.ShowInPads = Name;
                                ParameterCreated?.Invoke(this, cp);
                            }
                        }
                    }
                    break;
                case ToolTypeName.sdjd:
                    PointBase[] pts = PickPoints(3, false);
                    if (pts != null)
                    {
                        cp = new ThreePointsAngleParameter(this,
                            StdObjName($"∠{pts[0].Name}{pts[1].Name}{pts[2].Name}", false), pts[1], pts[0], pts[2]);
                        cp.ShowInPads = Name;
                        ParameterCreated?.Invoke(this, cp);
                    }
                    break;
                case ToolTypeName.ldjl:
                    pts = PickPoints(2);
                    if (pts != null)
                    {
                        for (int i = 0; i < pts.Length - 1; i++)
                        {
                            for (int j = i + 1; j < pts.Length; j++)
                            {
                                cp = new TwoPointsDistanceParameter(this, StdObjName("d", false), pts[i], pts[j]);
                                cp.ShowInPads = Name;
                                ParameterCreated?.Invoke(this, cp);
                            }
                        }
                    }
                    break;
                case ToolTypeName.ddzxdjl:
                    sls = PickStraightLines(1);
                    pts = PickPoints(1);
                    if (sls != null && pts != null)
                    {
                        for (int i = 0; i < pts.Length; i++)
                        {
                            for (int j = 0; j < sls.Length; j++)
                            {
                                cp = new PointStraightLineDistanceParameter(this, StdObjName("d", false), pts[i], sls[j]);
                                cp.ShowInPads = Name;
                                ParameterCreated?.Invoke(this, cp);
                            }
                        }
                    }
                    break;
                case ToolTypeName.lzxjl:
                    sls = PickStraightLines(2);
                    if (sls != null)
                    {
                        for (int i = 0; i < sls.Length - 1; i++)
                        {
                            for (int j = i + 1; j < sls.Length; j++)
                            {
                                if (sls[i].Slope.AlmostEqual(sls[j].Slope))
                                {
                                    cp = new TwoStraightLinesDistanceParameter(this, StdObjName("d", false), sls[i], sls[j]);
                                    cp.ShowInPads = Name;
                                    ParameterCreated?.Invoke(this, cp);
                                }
                            }
                        }
                    }
                    break;
                case ToolTypeName.lxldslj:
                    VectorBase[] vs = PickVectors(2);
                    if (vs != null)
                    {
                        for (int i = 0; i < vs.Length - 1; i++)
                        {
                            for (int j = i + 1; j < vs.Length; j++)
                            {
                                cp = new TwoVectorsScalarProductParameter(this, StdObjName("ScalarProduct"), vs[i], vs[j]);
                                cp.ShowInPads = Name;
                                ParameterCreated?.Invoke(this, cp);
                            }
                        }
                    }
                    break;
                case ToolTypeName.lxldxlj:
                    vs = PickVectors(2);
                    if (vs != null)
                    {
                        for (int i = 0; i < vs.Length - 1; i++)
                        {
                            for (int j = i + 1; j < vs.Length; j++)
                            {
                                cp = new TwoVectorsCrossProductParameter(this, StdObjName("CrossProduct"), vs[i], vs[j]);
                                cp.ShowInPads = Name;
                                ParameterCreated?.Invoke(this, cp);
                            }
                        }
                    }
                    break;
                case ToolTypeName.lzxdj:
                    LineBase[] lines = PickDirectedAngles(1);
                    if (lines != null)
                    {
                        if (lines.Length == 1)
                        {
                            cp = new TwoStraightLinesArrivalAngleParameter(this, StdObjName("ArrivalAngle"),
                                null, lines[0] as IDirectedAngle, UIInteraction.ObjectArguments.SaveRound);
                            cp.ShowInPads = Name;
                            ParameterCreated?.Invoke(this, cp);
                        }
                        else
                        {
                            for (int i = 0; i < lines.Length - 1; i++)
                            {
                                for (int j = i + 1; j < lines.Length; j++)
                                {
                                    cp = new TwoStraightLinesArrivalAngleParameter(this, StdObjName("ArrivalAngle"),
                                        lines[i] as IDirectedAngle, lines[j] as IDirectedAngle, UIInteraction.ObjectArguments.SaveRound);
                                    cp.ShowInPads = Name;
                                    ParameterCreated?.Invoke(this, cp);
                                }
                            }
                        }
                    }
                    break;
                default:
                    throw new ArgumentException();
            }
        }
        public bool BuildOnce()
        {
            try
            {
                BuildComponents(SelectedToolType);
                return true;
            }
            catch (Exception)
            {

            }
            try
            {
                BuildCalculatedParameter(SelectedToolType);
                return true;
            }
            catch (Exception)
            {

            }
            return false;
        }
        public void BuildComponents(ToolTypeName type)
        {
            switch (type)
            {
                case ToolTypeName.sjxnx:
                    PolygonBase[] polys = PickPolygons(1, Resources.Translate("Triangle"), (PolygonBase pol) => { return pol.LinesCount == 3; });
                    if (polys != null)
                    {
                        foreach (PolygonBase item in polys)
                        {
                            if (CoordinateType == CoordinateSystemType.PolarCoordinate)
                            {
                                HostObj = new PInCenter(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item);
                            }
                            else
                            {
                                HostObj = new RInCenter(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item);
                            }
                            HostObj.ShowItalicNameProperty();
                            CreateAndCommand(HostObj);
                        }
                    }
                    break;
                case ToolTypeName.sjxwx:
                    polys = PickPolygons(1, Resources.Translate("Triangle"), (PolygonBase pol) => { return pol.LinesCount == 3; });
                    if (polys != null)
                    {
                        foreach (PolygonBase item in polys)
                        {
                            if (CoordinateType == CoordinateSystemType.PolarCoordinate)
                            {
                                HostObj = new PCircumCenter(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item);
                            }
                            else
                            {
                                HostObj = new RCircumCenter(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item);
                            }
                            HostObj.ShowItalicNameProperty();
                            CreateAndCommand(HostObj);
                        }
                    }
                    break;
                case ToolTypeName.sjxcx:
                    polys = PickPolygons(1, Resources.Translate("Triangle"), (PolygonBase pol) => { return pol.LinesCount == 3; });
                    if (polys != null)
                    {
                        foreach (PolygonBase item in polys)
                        {
                            if (CoordinateType == CoordinateSystemType.PolarCoordinate)
                            {
                                HostObj = new POrthoCenter(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item);
                            }
                            else
                            {
                                HostObj = new ROrthoCenter(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item);
                            }
                            HostObj.ShowItalicNameProperty();
                            CreateAndCommand(HostObj);
                        }
                    }
                    break;
                case ToolTypeName.dbxzx:
                    polys = PickPolygons(1);
                    if (polys != null)
                    {
                        foreach (PolygonBase item in polys)
                        {
                            if (CoordinateType == CoordinateSystemType.PolarCoordinate)
                            {
                                HostObj = new PBaryCenter(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item);
                            }
                            else
                            {
                                HostObj = new RBaryCenter(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item);
                            }
                            HostObj.ShowItalicNameProperty();
                            CreateAndCommand(HostObj);
                        }
                    }
                    break;
                case ToolTypeName.zcx:
                    LineSegmentBase[] lss = PickLineSegments(1);
                    if (lss != null)
                    {
                        foreach (LineSegmentBase item in lss)
                        {
                            HostObj = new PerpendicularBisector(this, StdObjName(nameof(PerpendicularBisector)), item);
                            CreateAndCommand(HostObj);
                        }
                    }
                    break;
                case ToolTypeName.zd:
                    LineBase[] lines = PickLines(1, string.Format(Resources.Translate("Or"), Resources.Translate("LineSegment"), Resources.Translate("Arc")), (LineBase line) =>
                    {
                        return line is LineSegmentBase || line.ToolType == ToolTypeName.sdyh;
                    });
                    if (lines != null)
                    {
                        foreach (LineBase item in lines)
                        {
                            if (CoordinateType == CoordinateSystemType.PolarCoordinate)
                            {
                                HostObj = new PMidPoint(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item);
                            }
                            else
                            {
                                HostObj = new RMidPoint(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item);
                            }
                            HostObj.ShowItalicNameProperty();
                            CreateAndCommand(HostObj);
                        }
                    }
                    break;
                case ToolTypeName.wjy:
                    polys = PickPolygons(1);
                    if (polys != null)
                    {
                        foreach (PolygonBase item in polys)
                        {
                            HostObj = new CircumCircle(this, StdObjName(nameof(CircumCircle)), item);
                            CreateAndCommand(HostObj);
                        }
                    }
                    break;
                case ToolTypeName.nqy:
                    polys = PickPolygons(1);
                    if (polys != null)
                    {
                        foreach (PolygonBase item in polys)
                        {
                            HostObj = new InscribedCircle(this, StdObjName(nameof(InscribedCircle)), item);
                            CreateAndCommand(HostObj);
                        }
                    }
                    break;
                case ToolTypeName.zx:
                    lines = PickLines(1, Resources.Translate("CenterIncluded"),
                        (LineBase line) => { return line is ICenter || line is ArbitraryPolygon && (line as ArbitraryPolygon).IsRegularPolygon; });
                    if (lines != null)
                    {
                        foreach (LineBase item in lines)
                        {
                            if (CoordinateType == CoordinateSystemType.PolarCoordinate)
                            {
                                HostObj = new PShapeCenter(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item);
                            }
                            else
                            {
                                HostObj = new RShapeCenter(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item);
                            }
                            HostObj.ShowItalicNameProperty();
                            CreateAndCommand(HostObj);
                        }
                    }
                    break;
                case ToolTypeName.jpfx:
                    StraightLineBase[] sls = PickStraightLines(2);
                    if (sls != null)
                    {
                        for (int i = 0; i < sls.Length - 1; i++)
                        {
                            for (int j = i + 1; j < sls.Length; j++)
                            {
                                HostObj = new AngleBisector(this, StdObjName(nameof(AngleBisector)), sls[i], sls[j]);
                                CreateAndCommand(HostObj);
                            }
                        }
                    }
                    break;
                case ToolTypeName.jd:
                    lines = PickLines(2, Resources.Translate("Curve"));
                    if (lines != null)
                    {
                        for (int i = 0; i < lines.Length - 1; i++)
                        {
                            for (int j = i + 1; j < lines.Length; j++)
                            {
                                if (lines[i].HasCommonInHost(lines[j])) continue;
                                HostObj = new CrossoverPointsManager_A(this, StdObjName("CrossoverPoint"), lines[i], lines[j]);
                                CreateAndCommand(HostObj);
                            }
                        }
                    }
                    break;
                case ToolTypeName.qx:
                    lines = PickLines(1, Resources.Translate("Curve"), (LineBase line) =>
                    {
                        return line is ICurveLike;
                    });
                    PointBase[] pts = PickPoints(1);
                    if (lines != null && pts != null)
                    {
                        for (int i = 0; i < lines.Length; i++)
                        {
                            for (int j = 0; j < pts.Length; j++)
                            {
                                HostObj = new TangentLinesManager_A(this, StdObjName(nameof(TangentLine)), lines[i], pts[j]);
                                CreateAndCommand(HostObj);
                            }
                        }
                    }
                    break;
                case ToolTypeName.dhs:
                    lines = PickLines(1, Resources.Translate("Function"), (LineBase line) =>
                    {
                        return line is Function;
                    });
                    if (lines != null)
                    {
                        foreach (Function item in lines)
                        {
                            HostObj = new DerivationFunction(this, StdObjName("DerivedFunction"), item, FullScreenMode ? 1 : UIInteraction.ObjectArguments.DerivationFunctionOrder);
                            CreateAndCommand(HostObj);
                        }
                    }
                    break;
                case ToolTypeName.zbd:
                    //double arg1, arg2;
                    //try
                    //{
                    //    arg1 = Calculation.Calculate(UIInteraction.ObjectArguments.XExpression);
                    //}
                    //catch (Exception)
                    //{
                    //    MessageBox.Show(string.Format(Resources.Translate("InvalidExpression"), UIInteraction.ObjectArguments.XExpression),
                    //        Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                    //    return;
                    //}
                    //try
                    //{
                    //    arg2 = Calculation.Calculate(UIInteraction.ObjectArguments.YExpression);
                    //}
                    //catch (Exception)
                    //{
                    //    MessageBox.Show(string.Format(Resources.Translate("InvalidExpression"), UIInteraction.ObjectArguments.YExpression),
                    //        Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                    //    return;
                    //}
                    if (CoordinateType == CoordinateSystemType.PolarCoordinate)
                    {
                        HostObj = new PPoint_Fixed(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), UIInteraction.ObjectArguments.XExpression, UIInteraction.ObjectArguments.YExpression);
                    }
                    else
                    {
                        HostObj = new RPoint_Fixed(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), UIInteraction.ObjectArguments.XExpression, UIInteraction.ObjectArguments.YExpression);
                    }
                    HostObj.ShowItalicNameProperty();
                    CreateAndCommand(HostObj);
                    break;
                case ToolTypeName.csfc:
                    HostObj = new ParametricEquation(this, $"x = {UIInteraction.ObjectArguments.XExpression}, y = {UIInteraction.ObjectArguments.YExpression}", UIInteraction.ObjectArguments.XExpression, UIInteraction.ObjectArguments.YExpression);
                    CreateAndCommand(HostObj);
                    break;
                case ToolTypeName.dbfd:
                    if (!Calculation.Calculate(UIInteraction.ObjectArguments.CommonValue, out double arg1))
                    {
                        MessageBox.Show(string.Format(Resources.Translate("InvalidExpression"), UIInteraction.ObjectArguments.CommonValue), Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                    if (arg1 == -1)
                    {
                        MessageBox.Show(string.Format("RatioCannotBe-1"), Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                    lines = PickLines(1, string.Format(Resources.Translate("Or"), Resources.Translate("LineSegment"), Resources.Translate("Arc")), (LineBase line) =>
                    {
                        return line is LineSegmentBase || line.ToolType == ToolTypeName.sdyh;
                    });
                    if (lines != null)
                    {
                        foreach (LineBase item in lines)
                        {
                            if (CoordinateType == CoordinateSystemType.PolarCoordinate)
                            {
                                HostObj = new PProportionatePoint(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item, UIInteraction.ObjectArguments.CommonValue);
                            }
                            else
                            {
                                HostObj = new RProportionatePoint(this, StdObjName('A'.GetNextLetter(PointCount++), false, false), item, UIInteraction.ObjectArguments.CommonValue);
                            }
                            HostObj.ShowItalicNameProperty();
                            CreateAndCommand(HostObj);
                        }
                    }
                    break;
                case ToolTypeName.jndfx:
                    if (!Calculation.Calculate(UIInteraction.ObjectArguments.CommonValue, out arg1))
                    {
                        MessageBox.Show(string.Format(Resources.Translate("InvalidExpression"), UIInteraction.ObjectArguments.CommonValue), Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                    int dfs = (int)arg1;
                    if (dfs < 2)
                    {
                        MessageBox.Show(string.Format("DivisionNumberLess2"), Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                    sls = PickStraightLines(2);
                    if (sls != null)
                    {
                        for (int i = 0; i < sls.Length - 1; i++)
                        {
                            for (int j = i + 1; j < sls.Length; j++)
                            {
                                HostObj = new AngleNDivider(this, StdObjName(string.Format(Resources.Translate("AngleNumDivider"), dfs), false), ToolTypeName.jndfx, sls[i], sls[j], dfs);
                                CreateAndCommand(HostObj);
                            }
                        }
                    }
                    break;
                case ToolTypeName.yzb:
                case ToolTypeName.ygb:
                    PenBase pen = HostObj as PenBase;
                    if (pen != null)
                    {
                        pen.Complete();
                    }
                    break;
                default:
                    throw new ArgumentException();
            }
        }
        void ChangeCurveAccuracy(bool reduce)
        {
            if (Settings.Instance.AutoReduceAccuracy)
            {
                ForEachObject((Base obj) =>
                {
                    ICurve cur = obj as ICurve;
                    if (cur != null)
                    {
                        if (reduce)
                        {
                            if (oldCurveAccuracyExpression.ContainsKey(cur))
                            {
                                oldCurveAccuracyExpression[cur] = cur.Accuracy.DirectExpression;
                            }
                            else
                            {
                                oldCurveAccuracyExpression.Add(cur, cur.Accuracy.DirectExpression);
                            }
                            cur.Accuracy.SetExpression(10);
                        }
                        else
                        {
                            if (oldCurveAccuracyExpression.TryGetValue(cur, out string old))
                            {
                                cur.Accuracy.SetExpression(old);
                            }
                        }
                    }
                    return true;
                });
                if (!reduce)
                {
                    oldCurveAccuracyExpression.Clear();
                }
            }
        }
        void Canvas_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            NewMouseEventLocation = mouseDownLocation = e.Location;
            NewPLocation = MouseLocationToPxy(e.Location);
            switch (e.Button)
            {
                case MouseButtons.Left:
                    switch (SelectedToolType)
                    {
                        case ToolTypeName.ydhb:
                            Canvas.Cursor = new Cursor(Resource.Properties.Resources.cursor_drag_hand.GetHicon());
                            ChangeCurveAccuracy(true);
                            break;
                        case ToolTypeName.sf:
                            if (Flags.Shift)
                            {
                                ZoomOut(Settings.Instance.ZoomDelta);
                            }
                            else
                            {
                                ZoomIn(Settings.Instance.ZoomDelta);
                            }
                            translate.SetSeparately(translate.X.Value - e.X + Canvas.Width / 2,
                                translate.Y.Value - e.Y + Canvas.Height / 2);
                            break;
                        case ToolTypeName.yddx:
                            //ChangeCurveAccuracy(true);
                            OperateRing((Ring rng) => { rng.Visible = false; });
                            //ShowCursor(1);
                            foreach (Base item in AbsorbedObjects)
                            {
                                if (item.Movable)
                                {
                                    ShapeBase sb = item as ShapeBase;
                                    if (sb != null)
                                    {
                                        MoveObject_DoMouseDown(sb);
                                    }
                                }
                            }
                            break;
                        case ToolTypeName.qhdlx:
                            foreach (Base item in AbsorbedObjects)
                            {
                                switch (item.ToolType)
                                {
                                    case ToolTypeName.zyd:
                                        OldCoordinate = Coordinate;
                                        (item as PointBase).ConvertType(ToolTypeName.zbd);
                                        OldCoordinate = null;
                                        break;
                                    case ToolTypeName.zbd:
                                        OldCoordinate = Coordinate;
                                        (item as PointBase).ConvertType(ToolTypeName.zyd);
                                        OldCoordinate = null;
                                        break;
                                }
                            }
                            break;
                        default:
                            if (HostObj == null)//新建
                            {
                                switch (SelectedToolType)
                                {
                                    case ToolTypeName.zz:
                                        if (!Flags.Ctrl)
                                        {
                                            SelectNothing();
                                        }
                                        foreach (Base item in AbsorbedObjects)
                                        {
                                            item.SetInPicker(!Flags.Ctrl || !item.Selected);
                                            styleBackup[item] = item.StyleState;
                                        }
                                        for (int i = Canvas.Controls.Count - 1; i >= 0; i--)
                                        {
                                            TextBox tb = Canvas.Controls[i] as TextBox;
                                            if (tb != null)
                                            {
                                                (tb.Tag as TextArea).Text = tb.Text;
                                                Canvas.Controls.RemoveAt(i);
                                            }
                                        }
                                        ToolObj = new RectangularPicker(this, NewPLocation);
                                        break;
                                    case ToolTypeName.zyd:
                                        HostObj = CreatePoint(StdObjName('A'.GetNextLetter(PointCount++), false, false), NewPLocation, true, true);
                                        HostObj.ShowItalicNameProperty();
                                        break;
                                    case ToolTypeName.zbd:
                                        HostObj = CreatePoint(StdObjName('A'.GetNextLetter(PointCount++), false, false), NewPLocation, true, true);
                                        HostObj.ShowItalicNameProperty();
                                        break;
                                    case ToolTypeName.jd:
                                        HostObj = CreatePoint(StdObjName('A'.GetNextLetter(PointCount++), false, false), NewPLocation, true, true);
                                        HostObj.ShowItalicNameProperty();
                                        break;
                                    case ToolTypeName.qx:
                                        LineBase[] ls = PickLines(0, Resources.Translate("Curve"), (LineBase line) =>
                                        {
                                            return line is ICurveLike;
                                        });
                                        if (ls != null)
                                        {
                                            bool outfunc = false;
                                            for (int i = 0; i < ls.Length; i++)
                                            {
                                                if (AbsorbedObjects.Contains(ls[i]))
                                                {
                                                    HostObj = new TangentLine(this, StdObjName(nameof(TangentLine)), ls[i]);
                                                }
                                                else
                                                {
                                                    if (ls[i] is Function)
                                                    {
                                                        outfunc = true;
                                                        continue;
                                                    }
                                                    HostObj = new TangentLinesManager_A(this, StdObjName(nameof(TangentLine)), ls[i], null);
                                                }
                                                CreateAndCommand(HostObj);
                                            }
                                            if (outfunc)
                                            {
                                                MessageBox.Show(Resources.Translate("NotSupportFunctionTangentLine"), Resources.Translate("Prompt"), MessageBoxButtons.OK, MessageBoxIcon.Information);
                                            }
                                        }
                                        else
                                        {
                                            foreach (Base item in AbsorbedObjects)
                                            {
                                                if (item is ICurveLike)
                                                {
                                                    HostObj = new TangentLine(this, StdObjName(nameof(TangentLine)), item as LineBase);
                                                    CreateAndCommand(HostObj);
                                                }
                                            }
                                        }
                                        HostObj = null;
                                        break;
                                    case ToolTypeName.qly:
                                        Function[] fs = PickFunctions(1, false);
                                        if (fs != null)
                                        {
                                            HostObj = new CurvatureCircle(this, StdObjName(nameof(CurvatureCircle)), fs[0]);
                                        }
                                        break;
                                    case ToolTypeName.rydbx:
                                        HostObj = new ArbitraryPolygon(this, StdObjName(nameof(ArbitraryPolygon)));
                                        break;
                                    case ToolTypeName.zjsjx:
                                        HostObj = new RightTriangle(this, StdObjName(nameof(RightTriangle)));
                                        break;
                                    case ToolTypeName.dysjx:
                                        HostObj = new IsoscelesTriangle(this, StdObjName(nameof(IsoscelesTriangle)));
                                        break;
                                    case ToolTypeName.zfx:
                                        HostObj = new Square(this, StdObjName(nameof(Square)));
                                        break;
                                    case ToolTypeName.dyzjsjx:
                                        HostObj = new IsoscelesRightTriangle(this, StdObjName(nameof(IsoscelesRightTriangle)));
                                        break;
                                    case ToolTypeName.jx:
                                        HostObj = new Component.Polygon.Rectangle(this, StdObjName(nameof(Component.Polygon.Rectangle)));
                                        break;
                                    case ToolTypeName.lx:
                                        HostObj = new Diamond(this, StdObjName(nameof(Diamond)));
                                        break;
                                    case ToolTypeName.pxsbx:
                                        HostObj = new Parallelogram(this, StdObjName(nameof(Parallelogram)));
                                        break;
                                    case ToolTypeName.dbsjx:
                                        HostObj = new EquilateralTriangle(this, StdObjName(nameof(EquilateralTriangle)));
                                        break;
                                    case ToolTypeName.tx:
                                        HostObj = new Trapezoid(this, StdObjName(nameof(Trapezoid)));
                                        break;
                                    case ToolTypeName.zjtx:
                                        HostObj = new RightAngledTrapezoid(this, StdObjName(nameof(RightAngledTrapezoid)));
                                        break;
                                    case ToolTypeName.dytx:
                                        HostObj = new IsoscelesTrapezoid(this, StdObjName(nameof(IsoscelesTrapezoid)));
                                        break;
                                    case ToolTypeName.ysj:
                                        HostObj = new ConstrainedAngle(this, StdObjName(Resources.JoinLocalizedString("Constrained", "Angle"), false), UIInteraction.ObjectArguments.CommonValue);
                                        break;
                                    case ToolTypeName.ysty:
                                        HostObj = new ConstrainedEllipse(this, StdObjName(Resources.JoinLocalizedString("Constrained", "Ellipse"), false), UIInteraction.ObjectArguments.EllipseLongAxisHalfLength, UIInteraction.ObjectArguments.EllipseShortAxisHalfLength, UIInteraction.ObjectArguments.EllipseFocusAngle);
                                        break;
                                    case ToolTypeName.yssqx:
                                        HostObj = new ConstrainedHyperbola(this, StdObjName(Resources.JoinLocalizedString("Constrained", "Hyperbola"), false), UIInteraction.ObjectArguments.HyperbolaRealAxisHalfLength, UIInteraction.ObjectArguments.HyperbolaImaginaryAxisHalfLength, UIInteraction.ObjectArguments.HyperbolaFocusAngle);
                                        break;
                                    case ToolTypeName.yspwx:
                                        HostObj = new ConstrainedParabola(this, StdObjName(Resources.JoinLocalizedString("Constrained", "Parabola"), false), UIInteraction.ObjectArguments.ParabolaFocusDirectrixDistance, UIInteraction.ObjectArguments.ParabolaFocusAngle);
                                        break;
                                    case ToolTypeName.yxysxd:
                                        if (UIInteraction.ObjectArguments.DirectedConstrainedLineSegmentLength != null && UIInteraction.ObjectArguments.DirectedConstrainedLineSegmentLength == string.Empty ||
                                            UIInteraction.ObjectArguments.DirectedConstrainedLineSegmentDirectedAngle != null && UIInteraction.ObjectArguments.DirectedConstrainedLineSegmentDirectedAngle == string.Empty)
                                        {
                                            ShowMessage(string.Format(Resources.Translate("Or"), Resources.Translate("LSLength"), Resources.Translate("DirectedAngle")) + Resources.Join + Resources.Translate("CannotBeEmpty"), MessageType.Error);
                                        }
                                        else
                                        {
                                            HostObj = new DirectedConstrainedLineSegment(this, StdObjName('a'.GetNextLetter(StraightLineCount++), false, false), UIInteraction.ObjectArguments.DirectedConstrainedLineSegmentDirectedAngle, UIInteraction.ObjectArguments.DirectedConstrainedLineSegmentLength);
                                            HostObj.ShowItalicNameProperty();
                                        }
                                        break;
                                    case ToolTypeName.ysxl:
                                        if (string.IsNullOrEmpty(UIInteraction.ObjectArguments.ConstrainedVectorLength) ||
                                            string.IsNullOrEmpty(UIInteraction.ObjectArguments.ConstrainedVectorDirectedAngle))
                                        {
                                            ShowMessage(string.Format(Resources.Translate("Or"), Resources.Translate("VecLength"), Resources.Translate("DirectedAngle")) + Resources.Join + Resources.Translate("CannotBeEmpty"), MessageType.Error);
                                        }
                                        else
                                        {
                                            HostObj = new ConstrainedVector(this, StdObjName(Resources.JoinLocalizedString("Constrained", "Vector"), false), UIInteraction.ObjectArguments.ConstrainedVectorDirectedAngle, UIInteraction.ObjectArguments.ConstrainedVectorLength);
                                        }
                                        break;
                                    case ToolTypeName.ldxl:
                                        HostObj = new TwoPointsVector(this, StdObjName(nameof(TwoPointsVector)));
                                        break;
                                    case ToolTypeName.pxxl:
                                        StraightLineBase[] sls = PickStraightLines(1, false);
                                        if (sls != null)
                                        {
                                            HostObj = new ParallelVector(this, StdObjName(nameof(ParallelVector)), sls[0]);
                                        }
                                        break;
                                    case ToolTypeName.czxl:
                                        sls = PickStraightLines(1, false);
                                        if (sls != null)
                                        {
                                            HostObj = new VerticalVector(this, StdObjName(nameof(VerticalVector)), sls[0]);
                                        }
                                        break;
                                    case ToolTypeName.xljf:
                                        VectorBase[] vs = PickVectors(2);
                                        if (vs != null)
                                        {
                                            for (int i = 0; i < vs.Length - 1; i++)
                                            {
                                                for (int j = i + 1; j < vs.Length; j++)
                                                {
                                                    HostObj = new TwoVectorsAddition(this, StdObjName(nameof(TwoVectorsAddition)), vs[i], vs[j]);
                                                    CreateAndCommand(HostObj);
                                                }
                                            }
                                        }
                                        break;
                                    case ToolTypeName.xljf_:
                                        vs = PickVectors(2);
                                        if (vs != null)
                                        {
                                            for (int i = 0; i < vs.Length - 1; i++)
                                            {
                                                for (int j = i + 1; j < vs.Length; j++)
                                                {
                                                    HostObj = new TwoVectorsSubtraction(this, StdObjName(nameof(TwoVectorsSubtraction)), vs[i], vs[j]);
                                                    CreateAndCommand(HostObj);
                                                }
                                            }
                                        }
                                        break;
                                    case ToolTypeName.cx:
                                        sls = PickStraightLines(1);
                                        if (sls != null)
                                        {
                                            foreach (StraightLineBase item in sls)
                                            {
                                                HostObj = new VerticalLine(this, StdObjName(nameof(VerticalLine)), item);
                                                CreateAndCommand(HostObj);
                                            }
                                        }
                                        break;
                                    case ToolTypeName.pxx:
                                        sls = PickStraightLines(1);
                                        if (sls != null)
                                        {
                                            foreach (StraightLineBase item in sls)
                                            {
                                                HostObj = new ParallelLine(this, StdObjName(nameof(ParallelLine)), item);
                                                CreateAndCommand(HostObj);
                                            }
                                        }
                                        break;
                                    case ToolTypeName.cxd:
                                        sls = PickStraightLines(1);
                                        if (sls != null)
                                        {
                                            foreach (StraightLineBase item in sls)
                                            {
                                                HostObj = new VerticalLineSegment(this, StdObjName(nameof(VerticalLineSegment)), item);
                                                CreateAndCommand(HostObj);
                                            }
                                        }
                                        break;
                                    case ToolTypeName.ldxd:
                                        HostObj = new TwoPointsLineSegment(this, StdObjName('a'.GetNextLetter(StraightLineCount++), false, false));
                                        HostObj.ShowItalicNameProperty();
                                        break;
                                    case ToolTypeName.ldsx:
                                        HostObj = new TwoPointsRay(this, StdObjName('a'.GetNextLetter(StraightLineCount++), false, false));
                                        HostObj.ShowItalicNameProperty();
                                        break;
                                    case ToolTypeName.ldzx:
                                        HostObj = new TwoPointsStraightLine(this, StdObjName('a'.GetNextLetter(StraightLineCount++), false, false));
                                        HostObj.ShowItalicNameProperty();
                                        break;
                                    case ToolTypeName.yszx:
                                        HostObj = new ConstrainedStraightLine(this, StdObjName(Resources.JoinLocalizedString("Constrained", "StraightLine"), false), UIInteraction.ObjectArguments.PointSlopeStraightLineSlope);
                                        break;
                                    case ToolTypeName.yssx:
                                        HostObj = new ConstrainedRay(this, StdObjName(Resources.JoinLocalizedString("Constrained", "Ray"), false), UIInteraction.ObjectArguments.CommonValue);
                                        break;
                                    case ToolTypeName.zdbx:
                                        if (!Calculation.Calculate(UIInteraction.ObjectArguments.CommonValue, out double lineCount))
                                        {
                                            ShowMessage(string.Format(Resources.Translate("InvalidExpression"), UIInteraction.ObjectArguments.CommonValue), MessageType.Error);
                                            return;
                                        }
                                        int bs = (int)lineCount;
                                        if (bs < 2)
                                        {
                                            ShowMessage(Resources.Translate("RegularPolygonLess2"), MessageType.Error);
                                            return;
                                        }
                                        HostObj = new RegularPolygon(this, StdObjName(nameof(RegularPolygon)), bs);
                                        break;
                                    case ToolTypeName.yxbjy:
                                        HostObj = new ConstrainedCircle(this, StdObjName(Resources.JoinLocalizedString("Constrained", "Circle"), false), UIInteraction.ObjectArguments.CommonValue);
                                        break;
                                    case ToolTypeName.yxddy:
                                        HostObj = new CenterPointCircle(this, StdObjName(nameof(CenterPointCircle)));
                                        break;
                                    case ToolTypeName.zjy:
                                        HostObj = new DiameterCircle(this, StdObjName(nameof(DiameterCircle)));
                                        break;
                                    case ToolTypeName.sdy:
                                        HostObj = new ThreePointsCircle(this, StdObjName(nameof(ThreePointsCircle)));
                                        break;
                                    case ToolTypeName.sdyh:
                                        HostObj = new ThreePointsArc(this, StdObjName(nameof(ThreePointsArc)));
                                        break;
                                    case ToolTypeName.sdsx:
                                        HostObj = new ThreePointsSector(this, StdObjName(nameof(ThreePointsSector)));
                                        break;
                                    case ToolTypeName.bjyxjsx:
                                        //if (!Calculation.IsValidExpression(ObjectArguments.RadiusCentralAngleSectorCentralAngle, false))
                                        //{
                                        //    ShowMessage(string.Format(Resources.Translate("InvalidExpression"), ObjectArguments.RadiusCentralAngleSectorCentralAngle), MessageType.Error);
                                        //    return;
                                        //}
                                        HostObj = new RadiusCentralAngleSector(this, StdObjName(nameof(RadiusCentralAngleSector)), UIInteraction.ObjectArguments.CommonValue);
                                        break;
                                    case ToolTypeName.xggx:
                                        HostObj = new ChordHeightArch(this, StdObjName(nameof(ChordHeightArch)), UIInteraction.ObjectArguments.CommonValue);
                                        break;
                                    case ToolTypeName.sdgx:
                                        HostObj = new ThreePointsArch(this, StdObjName(nameof(ThreePointsArch)));
                                        break;
                                    case ToolTypeName.cdzty:
                                        HostObj = new LongShortAxisEllipse(this, StdObjName(nameof(LongShortAxisEllipse)));
                                        break;
                                    case ToolTypeName.jdddty:
                                        HostObj = new FocusPointEllipse(this, StdObjName(nameof(FocusPointEllipse)));
                                        break;
                                    case ToolTypeName.sxzsqx:
                                        HostObj = new RealImaginaryAxisHyperbola(this, StdObjName(nameof(RealImaginaryAxisHyperbola)));
                                        break;
                                    case ToolTypeName.jdddsqx:
                                        HostObj = new FocusPointHyperbola(this, StdObjName(nameof(FocusPointHyperbola)));
                                        break;
                                    case ToolTypeName.jdxzsqx:
                                        HostObj = new FocusImaginaryAxisHyperbola(this, StdObjName(nameof(FocusImaginaryAxisHyperbola)));
                                        break;
                                    case ToolTypeName.jdzxsqx:
                                        sls = PickStraightLines(0);
                                        HostObj = new FocusDirectrixHyperbola(this, StdObjName(nameof(FocusDirectrixHyperbola)), sls?[0]);
                                        break;
                                    case ToolTypeName.jdzxty:
                                        sls = PickStraightLines(0);
                                        HostObj = new FocusDirectrixEllipse(this, StdObjName(nameof(FocusDirectrixEllipse)), sls?[0]);
                                        break;
                                    case ToolTypeName.jdzxpwx:
                                        sls = PickStraightLines(0);
                                        HostObj = new FocusDirectrixParabola(this, StdObjName(nameof(FocusDirectrixParabola)), sls?[0]);
                                        break;
                                    case ToolTypeName.tp:
                                        if (UIInteraction.ObjectArguments.CommonValue.Length < 4)
                                        {
                                            ShowMessage(Resources.Translate("InvalidImageAddress"), MessageType.Error);
                                        }
                                        else
                                        {
                                            if (!UIInteraction.ObjectArguments.CommonValue.Substring(0, 4).Equals("http", StringComparison.OrdinalIgnoreCase))
                                            {
                                                try
                                                {
                                                    FileInfo fi = new FileInfo(UIInteraction.ObjectArguments.CommonValue);
                                                    string ext = fi.Extension;
                                                    if (ext.Equals(".jpg", StringComparison.OrdinalIgnoreCase) ||
                                                        ext.Equals(".jpeg", StringComparison.OrdinalIgnoreCase) ||
                                                        ext.Equals(".bmp", StringComparison.OrdinalIgnoreCase) ||
                                                        ext.Equals(".png", StringComparison.OrdinalIgnoreCase) ||
                                                        ext.Equals(".gif", StringComparison.OrdinalIgnoreCase) ||
                                                        ext.Equals(".ico", StringComparison.OrdinalIgnoreCase) ||
                                                        ext.Equals(".emf", StringComparison.OrdinalIgnoreCase) ||
                                                        ext.Equals(".wmf", StringComparison.OrdinalIgnoreCase))
                                                    {
                                                        Image.FromFile(UIInteraction.ObjectArguments.CommonValue);
                                                    }
                                                    else
                                                    {
                                                        ShowMessage(string.Format(Resources.Translate("NotSupportFileFormat"), ext), MessageType.Error);
                                                        return;
                                                    }
                                                }
                                                catch (Exception ex)
                                                {
                                                    ShowMessage(ex.Message, MessageType.Error);
                                                    return;
                                                }
                                            }
                                            SizeSetter tpss = new SizeSetter(NewPLocation);
                                            tpss.CreateObject += (RectangleD rect) =>
                                            {
                                                Canvas.Cursor = Cursors.WaitCursor;
                                                Picture pic = new Picture(this, StdObjName(nameof(Picture)))
                                                {
                                                    SpareCoordinate_ = rect.Location
                                                };
                                                pic.FitSize = !rect.IsMassPoint;
                                                if (pic.FitSize)
                                                {
                                                    pic.Size.SetFromSizeD(rect.Size);
                                                }
                                                CreateAndCommand(pic);
                                                Canvas.Cursor = Cursors.Cross;
                                            };
                                            ToolObj = tpss;
                                        }
                                        break;
                                    case ToolTypeName.wb:
                                        SizeSetter wbss = new SizeSetter(NewPLocation);
                                        wbss.CreateObject += (RectangleD rect) =>
                                        {
                                            Canvas.Cursor = Cursors.WaitCursor;
                                            rect = rect.ToStandardRectangle();
                                            TextArea txt = new TextArea(this, StdObjName("Text"), UIInteraction.ObjectArguments.TextAreaText)
                                            {
                                                SpareCoordinate_ = rect.Location
                                            };
                                            txt.FitSize = !rect.IsMassPoint;
                                            if (txt.FitSize)
                                            {
                                                txt.Size.SetFromSizeD(rect.Size);
                                            }
                                            CreateAndCommand(txt);
                                            Canvas.Cursor = Cursors.Cross;
                                        };
                                        ToolObj = wbss;
                                        break;
                                    case ToolTypeName.ygb:
                                        HostObj = new Highlighter(this, StdObjName(nameof(Highlighter)), UIInteraction.ObjectArguments.HighlighterColor);
                                        break;
                                    case ToolTypeName.yzb:
                                        HostObj = new Ballpen(this, StdObjName(nameof(Ballpen)), UIInteraction.ObjectArguments.BallpenColor);
                                        break;
                                    case ToolTypeName.qyxp:
                                        RegionEraser re = new RegionEraser(NewPLocation);
                                        re.Erase += (IList<PointD> pts) =>
                                        {
                                            ForEachExistVisibleObject((Base obj) =>
                                            {
                                                PenBase pen = obj as PenBase;
                                                if (pen != null)
                                                {
                                                    for (int i = 0; i < pen.Paths.Count; i++)
                                                    {
                                                        for (int j = 0; j < pen.Paths[i].Count; j++)
                                                        {
                                                            if (pen.Paths[i][j].InRegion(pts))
                                                            {
                                                                pen.Split(i, j);
                                                                if (i < pen.Paths.Count)
                                                                {
                                                                    j--;
                                                                }
                                                                else
                                                                {
                                                                    break;
                                                                }
                                                            }
                                                        }
                                                    }
                                                    if (pen.IsEmpty)
                                                    {
                                                        pen.Delete();
                                                    }
                                                }
                                                return true;
                                            });
                                        };
                                        ToolObj = re;
                                        break;
                                }
                            }
                            if (HostObj != null)
                            {
                                LineBase line = HostObj as LineBase;
                                if (line != null && UIInteraction.ObjectArguments.OrderIndex > -1)
                                {
                                    line.OrderIndex = UIInteraction.ObjectArguments.OrderIndex;
                                }
                                CreateAndCommand(HostObj);
                            }
                            break;
                    }
                    break;
                case MouseButtons.Right:
                    foreach (Base item in AbsorbedObjects)
                    {
                        item.Selected = true;
                    }
                    ContextMenuStrip cms = CreateMenuForObject(SelectedObjects);
                    ToolStripItem[] items = new ToolStripItem[]
                    {
                        //撤销
                        new ToolStripMenuItem(Resources.TranslateMenuItem("Undo", 'U'), Resource.Properties.Resources.undo, (object sender_, EventArgs e_) =>
                        {
                            Undo();
                        }, Keys.Control | Keys.Z)
                        {
                            Enabled = undos.Count > 0,
                        },
                        //恢复
                        new ToolStripMenuItem(Resources.TranslateMenuItem("Redo", 'R'), Resource.Properties.Resources.redo, (object sender_, EventArgs e_) =>
                        {
                            Redo();
                        }, Keys.Control | Keys.Y)
                        {
                            Enabled = redos.Count > 0,
                        },
                        new ToolStripSeparator(),
                    };
                    for (int i = 0; i < items.Length; i++)
                    {
                        cms.Items.Insert(i, items[i]);
                    }
                    Canvas.ContextMenuStrip = cms;
                    break;
            }
            ToolObj?.MouseDown(new AuxiliaryTool.MouseEventArgs(NewPLocation, e.Button));
            OldMouseEventLocation = NewMouseEventLocation;
            OldPLocation = NewPLocation;
        }
        public ContextMenuStrip CreateMenuForObject(IEnumerable<Base> objs)
        {
            if (objs == null) return null;
            List<Base> tops = new List<Base>();
            List<PointBase> points = new List<PointBase>();
            List<LineBase> lines = new List<LineBase>();
            List<ParametricEquation> pes = new List<ParametricEquation>();
            bool enableClearTrack = false, showName = false, enableLock = false, enableUnlock = false,
                enableFront = true, enableBack = true, hasLayerItem = false, hasFreePoint = false,
                hasFixedPoint = false, showCoordinate = false;
            int frontSteps = int.MaxValue, backSteps = int.MaxValue, objCount = 0;
            foreach (Base item in objs)
            {
                if (item == null) continue;
                objCount++;
                if (item.IsTop)
                {
                    tops.Add(item);
                }
                ShapeBase sb = item as ShapeBase;
                if (sb != null)
                {
                    if (!enableClearTrack) enableClearTrack = true;
                    if (!enableLock && !sb.Locked) enableLock = true;
                    if (!enableUnlock && sb.Locked) enableUnlock = true;
                    PointBase pt = sb as PointBase;
                    if (pt != null)
                    {
                        if (!hasFreePoint && pt.ToolType == ToolTypeName.zyd)
                        {
                            hasFreePoint = true;
                        }
                        else if (!hasFixedPoint && pt.ToolType == ToolTypeName.zbd)
                        {
                            hasFixedPoint = true;
                        }
                        if (!showCoordinate && !pt.CoordinateDisplayer.Visible)
                        {
                            showCoordinate = true;
                        }
                        points.Add(pt);
                    }
                    else
                    {
                        LineBase line = sb as LineBase;
                        if (line != null)
                        {
                            lines.Add(line);
                            ParametricEquation pe = line as ParametricEquation;
                            if (pe != null)
                            {
                                pes.Add(pe);
                            }
                        }
                    }
                }
                if (!showName && !item.NameDisplayer.Visible)
                {
                    showName = true;
                }
                if (item.LayerItem != null)
                {
                    if (!hasLayerItem) hasLayerItem = true;
                    int tmp;
                    if (enableBack)
                    {
                        if ((tmp = Layer.BeforeCount(item.LayerItem)) == 0)
                        {
                            enableBack = false;
                        }
                        else
                        {
                            if (tmp < backSteps)
                            {
                                backSteps = tmp;
                            }
                        }
                    }
                    if (enableFront)
                    {
                        if ((tmp = Layer.AfterCount(item.LayerItem)) == 0)
                        {
                            enableFront = false;
                        }
                        else
                        {
                            if (tmp < frontSteps)
                            {
                                frontSteps = tmp;
                            }
                        }
                    }
                }
            }
            ContextMenuStrip cms = new ContextMenuStrip();
            ToolStripItem insItem;
            cms.Items.AddRange(new ToolStripItem[]
            {
                //刷新
                new ToolStripMenuItem(Resources.TranslateMenuItem("Refresh", 'E'), Resource.Properties.Resources.refresh, (object sender_, EventArgs e_)=>
                {
                    Canvas.Refresh();
                    RefreshMenuClick?.Invoke(this);
                }, Keys.F5),
                //置于顶层
                new ToolStripMenuItem(Resources.TranslateMenuItem("BringToFront", 'B'), Resource.Properties.Resources.bring_front, (object sender_, EventArgs e_)=>
                {
                    List<LayerItem> ls = new List<LayerItem>();
                    foreach (Base item in objs)
                    {
                        if (item.LayerItem != null)
                        {
                            ls.Add(item.LayerItem);
                        }
                    }
                    ls.Sort();
                    for (int i = ls.Count - 1; i >= 0 ; i--)
                    {
                        ls[i].Index += frontSteps + 1;
                    }
                    Document.Modified = true;
                })
                {
                    Enabled = hasLayerItem && enableFront,
                },
                //置于底层
                new ToolStripMenuItem(Resources.TranslateMenuItem("SendToBack", 'S'), Resource.Properties.Resources.send_back, (object sender_, EventArgs e_)=>
                {
                    List<LayerItem> ls = new List<LayerItem>();
                    foreach (Base item in objs)
                    {
                        if (item.LayerItem != null)
                        {
                            ls.Add(item.LayerItem);
                        }
                    }
                    ls.Sort();
                    foreach (LayerItem item in ls)
                    {
                        item.Index -= backSteps;//不能+1，因为画板是最底层
                    }
                    Document.Modified = true;
                })
                {
                    Enabled = hasLayerItem && enableBack,
                },
                new ToolStripSeparator(),
                //剪切
                new ToolStripMenuItem(Resources.TranslateMenuItem("Cut", 'T'), Resource.Properties.Resources.cut, (object sender_, EventArgs e_)=>
                {
                    IList<Base> res = Delete(tops, true);
                    if (res?.Count > 0)
                    {
                        CopyObject?.Invoke(this, res);
                    }
                }, Keys.Control | Keys.X)
                {
                    Enabled = tops.Count > 0,
                },
                //复制
                new ToolStripMenuItem(Resources.TranslateMenuItem("Copy", 'C'), Resource.Properties.Resources.copy, (object sender_, EventArgs e_)=>
                {
                    CopyObject?.Invoke(this, objs);
                }, Keys.Control | Keys.C)
                {
                    Enabled = objCount > 0,
                },
                //粘贴
                new ToolStripMenuItem(Resources.TranslateMenuItem("Paste", 'P'), Resource.Properties.Resources.paste, (object sender_, EventArgs e_)=>
                {
                    PasteObject?.Invoke(this);
                    Document.Modified = true;
                }, Keys.Control | Keys.V)
                {
                    Enabled = Flags.PasteObjectEnabled,
                },
                //删除
                new ToolStripMenuItem(Resources.TranslateMenuItem("Delete", 'D'), Resource.Properties.Resources.delete, (object sender_, EventArgs e_)=>
                {
                    bool sft = Flags.Shift;
                    if (sft)
                    {
                        if (MessageBox.Show(string.Format(Resources.Translate("DeleteObjectAsk"), Resources.Translate("Component")), Resources.Translate("Ask"), MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
                        {
                            return;
                        }
                    }
                    Delete(tops, !sft);
                }, Keys.Delete)
                {
                    Enabled = tops.Count > 0,
                },
                //清除轨迹
                new ToolStripMenuItem(Resources.JoinLocalizedString("Clear", "Track"), Resource.Properties.Resources.eraseTrack, (object sender_, EventArgs e_)=>
                {
                    foreach (Base item in objs)
                    {
                        ShapeBase sb = item as ShapeBase;
                        if (sb == null) continue;
                        sb.ClearTracks();
                        Document.Modified = true;
                    }
                })
                {
                    Enabled = enableClearTrack,
                },
                //锁定
                new ToolStripMenuItem(Resources.TranslateMenuItem("Lock", 'L'), Resource.Properties.Resources._lock, (object sender_, EventArgs e_)=>
                {
                    foreach (Base item in objs)
                    {
                        ShapeBase sb = item as ShapeBase;
                        if (sb == null) continue;
                        sb.Locked = true;
                        Document.Modified = true;
                    }
                }, Keys.Control | Keys.L)
                {
                    Enabled = enableLock,
                },
                //解锁
                new ToolStripMenuItem(Resources.Translate("Unlock"), Resource.Properties.Resources.unlock, (object sender_, EventArgs e_)=>
                {
                    foreach (Base item in objs)
                    {
                        ShapeBase sb = item as ShapeBase;
                        if (sb == null) continue;
                        sb.Locked = false;
                        Document.Modified = true;
                    }
                })
                {
                    Enabled = enableUnlock,
                },
                new ToolStripSeparator(),
                //复制样式
                new ToolStripMenuItem(Resources.JoinLocalizedString("Copy", "Style"), Resource.Properties.Resources.format_painter, (object sender_, EventArgs e_)=>
                {
                    CopyStyle?.Invoke(this, objs.First());
                }, Keys.Control | Keys.Shift | Keys.C)
                {
                    Enabled = objCount == 1,
                },
                //粘贴样式
                new ToolStripMenuItem(Resources.JoinLocalizedString("Paste", "Style"), null, (object sender_, EventArgs e_)=>
                {
                    PasteStyle?.Invoke(this, objs);
                    Document.Modified = true;
                }, Keys.Control | Keys.Shift | Keys.V)
                {
                    Enabled = Flags.PasteStyleEnabled,
                },
                insItem = new ToolStripSeparator(),
                //显示名称
                new ToolStripMenuItem(Resources.JoinLocalizedString(showName ? "Show" : "Hide", "Name"), null, (object sender_, EventArgs e_)=>
                {
                    foreach (Base item in objs)
                    {
                        item.NameDisplayer.Visible = showName;
                        Document.Modified = true;
                    }
                }),
                new ToolStripSeparator(),
                //查看属性
                new ToolStripMenuItem(Resources.JoinLocalizedString("View(v)", "Property"), Resource.Properties.Resources.properties, (object sender_, EventArgs e_)=>
                {
                    ViewPropertyMenuClick?.Invoke(this);
                }, Keys.F4),
            });
            int insIndex = cms.Items.IndexOf(insItem) + 1;
            //插入和点相关的菜单项
            if (points.Count > 0)
            {
                //点尺寸
                ToolStripMenuItem size = new ToolStripMenuItem(Resources.JoinLocalizedString("Point", "Size"), null);
                size.DropDownItems.AddRange(new ToolStripItem[]
                {
                    //大
                    new ToolStripMenuItem(Resources.TranslateMenuItem("Large", 'L'))
                    {
                        Tag = new Tuple<int, int>(8, 5),
                    },
                    //中
                    new ToolStripMenuItem(Resources.TranslateMenuItem("Medium", 'M'))
                    {
                        Tag = new Tuple<int, int>(5, 3),
                    },
                    //小
                    new ToolStripMenuItem(Resources.TranslateMenuItem("Small", 'S'))
                    {
                        Tag = new Tuple<int, int>(3, 2),
                    },
                });
                foreach (ToolStripMenuItem item in size.DropDownItems)
                {
                    item.Click += (object sender_, EventArgs e_) =>
                    {
                        ToolStripMenuItem menu = sender_ as ToolStripMenuItem;
                        Tuple<int, int> tp = menu.Tag as Tuple<int, int>;
                        foreach (PointBase pt in points)
                        {
                            pt.Size.SetExpression(tp.Item1);
                            pt.OutlineWidth.SetExpression(tp.Item2);
                        }
                        Document.Modified = true;
                    };
                }
                cms.Items.Insert(insIndex++, size);
                //点轮廓颜色
                ToolStripMenuItem olcl = new ToolStripMenuItem(Resources.Translate("OutlineColor") + "...", null, (object sender_, EventArgs e_) =>
                {
                    ColorDialog cd = new ColorDialog();
                    if (cd.ShowDialog() == DialogResult.OK)
                    {
                        foreach (PointBase pt in points)
                        {
                            pt.OutlineColor = cd.Color;
                        }
                        Document.Modified = true;
                    }
                });
                cms.Items.Insert(insIndex++, olcl);
                //点填充颜色
                ToolStripMenuItem fillcl = new ToolStripMenuItem(Resources.Translate("FillColor") + "...", null, (object sender_, EventArgs e_) =>
                {
                    ColorDialog cd = new ColorDialog();
                    if (cd.ShowDialog() == DialogResult.OK)
                    {
                        foreach (PointBase pt in points)
                        {
                            pt.FillColor = cd.Color;
                        }
                        Document.Modified = true;
                    }
                });
                cms.Items.Insert(insIndex++, fillcl);
                //显示坐标
                ToolStripMenuItem showco = new ToolStripMenuItem(Resources.JoinLocalizedString(showCoordinate? "Show":"Hide", "Coordinate"), null, (object sender_, EventArgs e_) =>
                {
                    foreach (PointBase item in points)
                    {
                        item.CoordinateDisplayer.Visible = showCoordinate;
                    }
                    Document.Modified = true;
                });
                cms.Items.Insert(insIndex++, showco);
                //生成点的动画
                ToolStripMenuItem makeani = new ToolStripMenuItem(Resources.Translate("CreateAnimationMenuDesc"), null, (object sender_, EventArgs e_) =>
                {
                    foreach (PointBase item in points)
                    {
                        AnimationBase ani;
                        if (Flags.HighPerformanceTimerEnabled)
                        {
                            ani = new HighPerformanceAnimation(item, "3");
                        }
                        else
                        {
                            ani = new NormalAnimation(item, "3");
                        }
                        Animations.Add(ani);
                        AddNewCommand(new AddObject<AnimationBase>(ani), false);
                        AnimationCreated?.Invoke(this, ani);
                        ani.Run();
                    }
                    Document.Modified = true;
                });
                cms.Items.Insert(insIndex++, makeani);
                cms.Items.Insert(insIndex++, new ToolStripSeparator());
            }
            //插入和线相关的菜单项
            if (lines.Count > 0)
            {
                //线粗细
                ToolStripMenuItem width = new ToolStripMenuItem(Resources.Translate("LineWidth"), null);
                width.DropDownItems.AddRange(new ToolStripItem[]
                {
                    //粗
                    new ToolStripMenuItem(Resources.TranslateMenuItem("Thick", 'C'))
                    {
                        Tag = 5,
                    },
                    //中
                    new ToolStripMenuItem(Resources.TranslateMenuItem("Medium", 'M'))
                    {
                        Tag = 3,
                    },
                    //细
                    new ToolStripMenuItem(Resources.TranslateMenuItem("Thin", 'N'))
                    {
                        Tag = 1,
                    },
                });
                foreach (ToolStripMenuItem item in width.DropDownItems)
                {
                    item.Click += (object sender_, EventArgs e_) =>
                    {
                        ToolStripMenuItem menu = sender_ as ToolStripMenuItem;
                        foreach (LineBase line in lines)
                        {
                            line.LineWidth.SetExpression((int)menu.Tag);
                        }
                        Document.Modified = true;
                    };
                }
                cms.Items.Insert(insIndex++, width);
                //线样式
                ToolStripMenuItem linestyle = new ToolStripMenuItem(Resources.Translate("LineDashStyle"), null);
                linestyle.DropDownItems.AddRange(new ToolStripItem[]
                {
                    //实线
                    new ToolStripMenuItem(Resources.Translate("Solid"))
                    {
                        Tag = DashStyle.Solid,
                    },
                    //虚线
                    new ToolStripMenuItem(Resources.Translate("Dash"))
                    {
                        Tag = DashStyle.Dash,
                    },
                    //点线
                    new ToolStripMenuItem(Resources.Translate("Dot"))
                    {
                        Tag = DashStyle.Dot,
                    },
                    //点划线
                    new ToolStripMenuItem(Resources.Translate("DashDot"))
                    {
                        Tag = DashStyle.DashDot,
                    },
                    //双点划线
                    new ToolStripMenuItem(Resources.Translate("DashDotDot"))
                    {
                        Tag = DashStyle.DashDotDot,
                    },
                });
                foreach (ToolStripMenuItem item in linestyle.DropDownItems)
                {
                    item.Click += (object sender_, EventArgs e_) =>
                    {
                        ToolStripMenuItem menu = sender_ as ToolStripMenuItem;
                        foreach (LineBase line in lines)
                        {
                            line.LineDashStyle = (DashStyle)menu.Tag;
                        }
                        Document.Modified = true;
                    };
                }
                cms.Items.Insert(insIndex++, linestyle);
                //线颜色
                ToolStripMenuItem cl = new ToolStripMenuItem(Resources.Translate("LineColor") + "...", null, (object sender_, EventArgs e_) =>
                {
                    ColorDialog cd = new ColorDialog();
                    if (cd.ShowDialog() == DialogResult.OK)
                    {
                        foreach (LineBase line in lines)
                        {
                            line.LineColor = cd.Color;
                        }
                        Document.Modified = true;
                    }
                });
                cms.Items.Insert(insIndex++, cl);
                cms.Items.Insert(insIndex++, new ToolStripSeparator());
            }
            //插入和参数方程相关的菜单项
            if (pes.Count > 0)
            {
                //清除图像
                ToolStripMenuItem clearImage = new ToolStripMenuItem(Resources.JoinLocalizedString("Clear", "Image"), null, (object sender_, EventArgs e_) =>
                {
                    foreach (ParametricEquation item in pes)
                    {
                        item.ClearImage();
                    }
                    Document.Modified = true;
                });
                cms.Items.Insert(insIndex++, clearImage);
                cms.Items.Insert(insIndex++, new ToolStripSeparator());
            }
            setMenuItemImageScaleToNone(cms.Items);
            ToolStripCreated?.Invoke(this, cms);
            return cms;
        }
        public IList<Base> Delete(IEnumerable<Base> objs, bool recoverable = false)
        {
            //复制一份，如果在原来列表上删除，当删除坐标系时，切换点类型后选中项列表将改变，引发错误
            List<Base> res = new List<Base>(objs.Where((Base obj) => { return obj.IsTop; }));
            if (res.Count == 0) return null;
            if (recoverable)
            {
                DeleteObjects<Base> del = new DeleteObjects<Base>(res);
                del.DeleteObject += LayerControl.DeleteObjectHandler;
                del.RecoverObject += LayerControl.RecoverObjectHandler;
                try
                {
                    del.Redo();
                }
                catch (Exception ex)
                {
                    HashSet<IRecoverableDelete> done = ex.Data["DeletedObjects"] as HashSet<IRecoverableDelete>;
                    if (done != null)
                    {
                        del.RemoveObjects((Base obj) => { return !done.Contains(obj); });
                        if (ex.Message != Flags.ExceptionShieldMessage)
                        {
                            MessageBox.Show(ex.Message, Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }
                }
                finally
                {
                    if (del.ObjectCount > 0)
                    {
                        AddNewCommand(del, false);
                    }
                }
            }
            else
            {
                //最后删除坐标系，防止先删除坐标系导致过多的点类型转换无用功
                bool delCS = false;
                foreach (Base item in res)
                {
                    if (item is CoordinateBase)
                    {
                        delCS = true;
                    }
                    else
                    {
                        item.Delete();
                    }
                }
                if (delCS)
                {
                    CoordinateType = CoordinateSystemType.None;
                }
            }
            Document.Modified = true;
            return res;
        }
        void setMenuItemImageScaleToNone(ToolStripItemCollection collection)
        {
            foreach (ToolStripItem item in collection)
            {
                ToolStripDropDownItem dd = item as ToolStripDropDownItem;
                if (dd != null)
                {
                    setMenuItemImageScaleToNone(dd.DropDownItems);
                }
                item.ImageScaling = ToolStripItemImageScaling.None;
            }
        }
        public void SelectAll(bool exceptPad = true)
        {
            foreach (LayerItem item in Layer.Items)
            {
                if (exceptPad && item.LinkedObj == null)
                {
                    continue;
                }
                item.Selected_ = true;
            }
        }
        public void SelectReverse(bool exceptPad = true)
        {
            foreach (LayerItem item in Layer.Items)
            {
                if (exceptPad && item.LinkedObj == null)
                {
                    continue;
                }
                item.Selected_ = !item.Selected_;
            }
        }
        public void ForEachObject(Predicate<Base> act, bool posSeq = false, bool all = true)
        {
            if (act == null) return;
            int step = posSeq ? 1 : -1;
            List<LayerItem> target = all ? Layer.Items : Layer.SelectedItems;
            for (int i = posSeq ? 0 : target.Count - 1; posSeq ? i < target.Count : i >= 0; i += step)
            {
                if (target[i].LinkedObj != null)
                {
                    if (!act(target[i].LinkedObj))
                    {
                        break;
                    }
                }
            }
        }
        public void ForEachExistObject(Predicate<Base> act, bool posSeq = false, bool all = true)
        {
            if (act == null) return;
            int step = posSeq ? 1 : -1;
            List<LayerItem> target = all ? Layer.Items : Layer.SelectedItems;
            for (int i = posSeq ? 0 : target.Count - 1; posSeq ? i < target.Count : i >= 0; i += step)
            {
                if (target[i].ObjectState == ObjectState.Normal && target[i].LinkedObj != null && target[i].LinkedObj.ObjectState == ObjectState.Normal)
                {
                    if (!act(target[i].LinkedObj))
                    {
                        break;
                    }
                }
            }
        }
        public void ForEachExistSingleObject(Predicate<Base> act)
        {
            if (act == null) return;
            HashSet<Base> set = new HashSet<Base>();
            ForEachExistObject((Base obj) =>
            {
                if (set.Add(obj))
                {
                    if (!act(obj))
                    {
                        return false;
                    }
                }
                ShapeBase sb = obj as ShapeBase;
                if (sb != null)
                {
                    sb.AllInChildrenIterator((ShapeBase shape) =>
                    {
                        if (set.Add(shape))
                        {
                            if (!act(shape))
                            {
                                return false;
                            }
                        }
                        return true;
                    });
                }
                return true;
            });
        }
        public void ForEachExistVisibleObject(Predicate<Base> act, bool posSeq = false, bool all = true)
        {
            if (act == null) return;
            int step = posSeq ? 1 : -1;
            List<LayerItem> target = all ? Layer.Items : Layer.SelectedItems;
            for (int i = posSeq ? 0 : target.Count - 1; posSeq ? i < target.Count : i >= 0; i += step)
            {
                if (target[i].ObjectState == ObjectState.Normal && target[i].LinkedObj != null && target[i].LinkedObj.ObjectState == ObjectState.Normal && target[i].LinkedObj.Visible)
                {
                    if (!act(target[i].LinkedObj))
                    {
                        break;
                    }
                }
            }
        }
        #region ComponentsPicker
        public T[] PickComponents<T>(int count, string lessErrMsg, Action<T, List<string>> extraInfo = null,
            string[] infoHeaders = null, Predicate<T> judge = null, bool canMore = true) where T : ShapeBase
        {
            if (count < 0) return null;
            HashSet<T> set = new HashSet<T>();
            foreach (Base item in SelectedObjects)
            {
                T tmp = item as T;
                if (tmp != null && (judge == null || judge(tmp)))
                {
                    set.Add(tmp);
                }
            }
            if (set.Count < count)
            {
                MessageBox.Show(string.Format(Resources.Translate("SelectNAtLeast"), count, lessErrMsg), Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                return null;
            }
            if (set.Count > count && !canMore)
            {
                ListViewItem[] items = new ListViewItem[set.Count];
                int i = 0;
                foreach (T item in set)
                {
                    List<string> infos = new List<string>();
                    infos.Add(item.Name);
                    extraInfo?.Invoke(item, infos);
                    items[i++] = new ListViewItem(infos.ToArray()) { Tag = item };
                }
                if (UIInteraction.PickComponent.PickComponents(items, count, string.Format(Resources.Translate("SelectNAtLeast"), count, lessErrMsg), infoHeaders) == DialogResult.OK)
                {
                    foreach (ListViewItem item in items)
                    {
                        if (!item.Checked)
                        {
                            set.Remove(item.Tag as T);
                        }
                    }
                }
                else
                {
                    return null;
                }
            }
            if (set.Count == 0) return null;
            //去除子集（可能有BUG）
            List<T> res = new List<T>(set);
            foreach (T item in set)
            {
                if (item.Selected_)
                {
                    item.AllInChildrenIterator((ShapeBase shape) =>
                    {
                        res.Remove(shape as T);
                        return true;
                    });
                }
            }
            return res.ToArray();
        }
        public void SelectNothing()
        {
            Layer.SelectNone();
            Base[] bkp = SelectedObjects.ToArray();
            foreach (Base item in bkp)
            {
                item.Selected = false;
                item.StyleState = StyleState.Normal;
            }
        }
        public StraightLineBase[] PickStraightLines(int count, bool canMore = true)
        {
            return PickComponents(count, string.Format(Resources.Translate("CompOrContainsComp"), Resources.Translate("StraightLine")), (StraightLineBase line, List<string> lst) =>
            {
                lst.Add(line.Location.ToString());
                lst.Add(line.Slope.ToString());
            }, new string[] { Resources.Translate("AnchorPoint"), Resources.Translate("Slope") }, null, canMore);
        }
        public VectorBase[] PickVectors(int count, bool canMore = true)
        {
            return PickComponents(count, Resources.Translate("Vector"), (VectorBase line, List<string> lst) =>
            {
                lst.Add(line.Point1.ToPointD().ToString());
                lst.Add(line.Point2.ToPointD().ToString());
            }, new string[] { Resources.JoinLocalizedString("StartPoint", "Coordinate"), Resources.JoinLocalizedString("TerminalPoint", "Coordinate") }, null, canMore);
        }
        public LineBase[] PickDirectedAngles(int count, bool canMore = true)
        {
            return PickComponents(count, Resources.Translate("StraightLineWithDirectedAngle"), (LineBase line, List<string> lst) =>
            {
                //if (line is IDirectedAngle)
                //{
                lst.Add(ShowRad((line as IDirectedAngle).DirectedAngle).ToString());
                //}
            }, new string[] { Resources.Translate("DirectedAngle") }, (LineBase line) =>
            {
                return line is IDirectedAngle;
            }, canMore);
        }
        public LineBase[] PickLines(int count, string lessErrMsg, Predicate<LineBase> rule = null, bool canMore = true)
        {
            return PickComponents(count, lessErrMsg, null, null, rule, canMore);
        }
        public PolygonBase[] PickPolygons(int count, string lessErrMsg = null, Predicate<PolygonBase> rule = null, bool canMore = true)
        {
            if (lessErrMsg == null)
            {
                lessErrMsg = Resources.Translate("Polygon");
            }
            return PickComponents(count, lessErrMsg, null, null, rule, canMore);
        }
        public Function[] PickFunctions(int count, bool canMore = true)
        {
            return PickComponents<Function>(count, Resources.Translate(nameof(Function)), null, null, null, canMore);
        }
        public LineSegmentBase[] PickLineSegments(int count, bool canMore = true)
        {
            return PickComponents(count, string.Format(Resources.Translate("Or"), Resources.Translate("LineSegment"), Resources.Translate("Vector")), (LineSegmentBase line, List<string> lst) =>
            {
                lst.Add(line.Point1.ToPointD().ToString());
                lst.Add(line.Point2.ToPointD().ToString());
            }, new string[] { $"{Resources.Translate("EndPoint")}1{Resources.LeftParenthesis}{Resources.Translate("StartPoint")}{Resources.RightParenthesis}{Resources.Join}{Resources.Translate("Coordinate")}", $"{Resources.Translate("EndPoint")}2{Resources.LeftParenthesis}{Resources.Translate("TerminalPoint")}{Resources.RightParenthesis}{Resources.Join}{Resources.Translate("Coordinate")}" }, null, canMore);
        }
        public PointBase[] PickPoints(int count, bool canMore = true)
        {
            List<PointBase> pts = new List<PointBase>();
            foreach (LayerItem item in Layer.SelectedItems)
            {
                PointBase pt = item.LinkedObj as PointBase;
                if (pt != null)
                {
                    pts.Add(pt);
                }
            }
            if (pts.Count >= count && canMore)
            {
                return pts.ToArray();
            }
            return PickComponents(count, string.Format(Resources.Translate("CompOrContainsComp"), Resources.Translate("Point")), (PointBase pt, List<string> lst) =>
            {
                lst.Add(pt.ToPointD().ToString());
            }, new string[] { Resources.Translate("Coordinate") }, null, canMore);
        }
        #endregion
        public PointD MathToPxy(PointD mathCoordinate)
        {
            if (Coordinate == null) return mathCoordinate;
            PolarCoordinate pc = Coordinate as PolarCoordinate;
            if (pc != null)
            {
                return pc.RTtoPxy(mathCoordinate);
            }
            else
            {
                return Coordinate.XYToPxy(mathCoordinate);
            }
        }
        public PointD PxyToMath(PointD Pxy)
        {
            if (Coordinate == null) return Pxy;
            PolarCoordinate pc = Coordinate as PolarCoordinate;
            if (pc != null)
            {
                return pc.PxytoRT(Pxy);
            }
            else
            {
                return Coordinate.PxyToXY(Pxy);
            }
        }
        public int CountToolType(ToolTypeName type)
        {
            int sum = 0;
            foreach (LayerItem item in Layer.Items)
            {
                if (item.ObjectState == ObjectState.Normal && item.LinkedObj?.ToolType == type)
                {
                    sum++;
                }
            }
            return sum;
        }
        public string StdObjName(string name, bool translate = true, bool appendIndex = true)
        {
            if (translate)
            {
                name = Resources.Translate(name);
            }
            if (appendIndex)
            {
                name += (CountToolType(SelectedToolType) + 1);
            }
            return Utility.GetNextAvailableName(name, CheckObjectNameExist);
        }
        public PointD MouseLocationToPxy(Point location)
        {
            PointD tmp = new PointD(location.X - translate.X.Value, location.Y - translate.Y.Value);
            if (Coordinate != null)
            {
                tmp -= Coordinate.OriginCoordinate.ToPointD();
            }
            return tmp / Zoom.ToPointD();
        }
        public Point PxyToMouseLocation(PointD Pxy)
        {
            PointD tmp = Pxy * Zoom.ToPointD();
            if (Coordinate != null)
            {
                tmp += Coordinate.OriginCoordinate.ToPointD();
            }
            tmp += translate.ToPointD();
            return tmp.ToPoint();
        }
        public PointD ConvertRPointS(RPointS rps, CoordinateBase oldCS)
        {
            return MathOldToNew(rps.ToMathCoordinate(), oldCS);
        }
        /// <summary>
        /// 以坐标等价转换数学坐标
        /// </summary>
        /// <param name="oldMath">要转换的数学坐标</param>
        /// <param name="oldCS">旧坐标所在坐标系</param>
        /// <returns></returns>
        public PointD MathOldToNew(PointD oldMath, CoordinateBase oldCS)
        {
            if (oldCS == null)
            {
                if (Coordinate != null)
                {
                    return PxyToMath(oldMath - Coordinate.OriginCoordinate.ToPointD() / Zoom.ToPointD());
                }
            }
            else
            {
                RectangularCoordinate oldRC = oldCS as RectangularCoordinate;
                if (oldRC != null)
                {
                    if (Coordinate == null)
                    {
                        return oldRC.XYToPxy(oldMath) + oldRC.OriginCoordinate.ToPointD() / Zoom.ToPointD();
                    }
                    else
                    {
                        PolarCoordinate newPC = Coordinate as PolarCoordinate;
                        if (newPC != null)
                        {
                            return newPC.XYtoRT(oldMath);
                        }
                    }
                }
                else
                {
                    PolarCoordinate oldPC = oldCS as PolarCoordinate;
                    if (oldPC != null)
                    {
                        if (Coordinate == null)
                        {
                            return oldPC.RTtoPxy(oldMath) + oldPC.OriginCoordinate.ToPointD() / Zoom.ToPointD();
                        }
                        else
                        {
                            //RectangularCoordinate newRC = Coordinate as RectangularCoordinate;
                            if (Coordinate is RectangularCoordinate)
                            {
                                return oldPC.RTtoXY(oldMath);
                            }
                        }
                    }
                }
            }
            return oldMath;
        }
        public void CopyOffset(ToolTypeName type, IList<PointD> pts)
        {
            while (LocationUsed(type, pts))
            {
                for (int i = 0; i < pts.Count; i++)
                {
                    pts[i] += Coordinate == null ? new SizeD(Settings.Instance.CopyOffset_WithoutCS_Width, Settings.Instance.CopyOffset_WithoutCS_Height) : new SizeD(Settings.Instance.CopyOffset_WithCS_Width, Settings.Instance.CopyOffset_WithCS_Height);
                }
            }
        }
        public void CopyOffset(ToolTypeName type, IList<PointCreatingArgs> args)
        {
            PointD[] pts = new PointD[args.Count];
            for (int i = 0; i < pts.Length; i++)
            {
                pts[i] = args[i].Location;
            }
            CopyOffset(type, pts);
            for (int i = 0; i < args.Count; i++)
            {
                args[i].Location = pts[i];
            }
        }
        public bool LocationUsed(ToolTypeName type, IList<PointD> locations)
        {
            bool used = false;
            ForEachExistVisibleObject((Base obj) =>
            {
                if (obj.ToolType == type)
                {
                    used = obj.LocationUsed(locations);
                }
                return !used;
            });
            return used;
        }
        //public PointD XYOldToNew(PointD oldXY, CoordinateBase oldCS)
        //{
        //    if (oldCS == null)
        //    {
        //        if (Coordinate != null)
        //        {
        //            return PxyToXY(oldXY - Coordinate.OriginCoordinate.ToPointD() / Zoom.ToPointD());
        //        }
        //    }
        //    else
        //    {
        //        if (Coordinate == null)
        //        {
        //            return oldCS.XYToPxy(oldXY) + oldCS.OriginCoordinate.ToPointD() / Zoom.ToPointD();
        //        }
        //    }
        //    return oldXY;
        //}
        public int Sign(PointD center, PointD oldpt, PointD newpt)
        {
            if (Utility.IsClockwise(center, oldpt, newpt))
            {
                return Coordinate == null ? 1 : -1;
            }
            else
            {
                return Coordinate == null ? -1 : 1;
            }
        }
        public bool CheckObjectNameExist(string name)
        {
            bool exist = false;
            ForEachExistObject((Base obj) =>
            {
                if (obj.Name == name)
                {
                    exist = true;
                }
                return !exist;
            });
            return exist;
        }
        /// <summary>
        /// 将点吸附到圆上
        /// </summary>
        /// <param name="pCenter">圆心坐标(P)</param>
        /// <param name="r">圆半径</param>
        /// <param name="pLocation">吸附前点的位置(P)</param>
        /// <returns>吸附后点的位置(P)</returns>
        public PointD FixOnCircle(PointD pCenter, double r, PointD pLocation)
        {
            double lambda = r / (Coordinate == null ? pCenter.DistanceTo(pLocation) : Coordinate.PxyToXY(pCenter).DistanceTo(Coordinate.PxyToXY(pLocation)));
            PointD result = pLocation - pCenter;
            result.X *= lambda;
            result.Y *= lambda;
            return result + pCenter;
        }
        public double GetVerticalLinePSlope(PointD Ppt1, PointD Ppt2)
        {
            return GetVerticalLinePSlope(Ppt1.GetSlope(Ppt2));
        }
        public double GetVerticalLinePSlope(double Pk)
        {
            if (Coordinate == null)
            {
                return -1 / Pk;
            }
            else
            {
                return Coordinate.kToPk(-1 / Coordinate.PkTok(Pk));
            }
        }
        /// <summary>
        /// 计算和弧有关的参数 [返回数组意义 >> 0:占圆比，1:半径，2:弧长，3:弦长，4:起始角（数学），5:起始角（绘图），6:扫角（数学），7:扫角（绘图）]
        /// </summary>
        /// <param name="pt1"></param>
        /// <param name="midXY"></param>
        /// <param name="midPxy"></param>
        /// <param name="pt2XY"></param>
        /// <param name="pt2Pxy"></param>
        /// <param name="center"></param>
        /// <param name="Pcenter"></param>
        /// <returns></returns>
        public double[] CalcArcParams(PointBase pt1, PointD? midXY, PointD midPxy, PointD? pt2XY, PointD pt2Pxy, ref PointD center, ref PointD Pcenter)
        {
            double[] res = new double[8];
            if (Coordinate == null)
            {
                center = Pcenter = Utility.GetCenter(pt1.NewPxy, midPxy, pt2Pxy);
                if (!pt2XY.HasValue)
                {
                    pt2XY = pt2Pxy;
                }
            }
            else
            {
                if (!midXY.HasValue)
                {
                    midXY = Coordinate.PxyToXY(midPxy);
                }
                if (!pt2XY.HasValue)
                {
                    pt2XY = Coordinate.PxyToXY(pt2Pxy);
                }
                center = Utility.GetCenter(pt1.NewXY, midXY.Value, pt2XY.Value);
                Pcenter = Coordinate.XYToPxy(center);
            }
            if (!Pcenter.IsPaintable) return null;
            res[6] = Utility.GetAngle(center, pt1.NewXY, pt2XY.Value);
            res[7] = Utility.GetAngle(Pcenter, pt1.NewPxy, pt2Pxy);
            res[0] = res[6] / Core.Helper.Angle.RadRound;
            res[4] = center.GetAngle(pt1.NewXY);
            res[5] = Pcenter.GetAngle(pt1.NewPxy);
            if (Coordinate != null)
            {
                res[5] += Coordinate.RotateAngle.RadValue;
            }
            if (Utility.OnSameSide(pt1.NewPxy, pt2Pxy, midPxy, Pcenter))
            {
                res[0] = 1 - res[0];
                res[7] = Core.Helper.Angle.RadRound - res[7];
                res[6] = Core.Helper.Angle.RadRound - res[6];
            }
            res[7] *= Utility.Sign(pt1.NewPxy, midPxy, pt2Pxy) * (pt1.NewPxy.X > midPxy.X ? 1 : -1);
            res[6] *= -Math.Sign(res[7]);
            res[1] = center.DistanceTo(pt1.NewXY);
            res[2] = Core.Helper.Angle.RadRound * res[1] * res[0];
            res[3] = pt1.NewXY.DistanceTo(pt2XY.Value);
            return res;
        }
        public double[] ABCtoPaPbPc(double A, double B, double C)
        {
            if (Coordinate == null)
            {
                return new double[] { A, B, C };
            }
            if (B == 0)
            {
                PointD tmp = Coordinate.XYToPxy(new PointD(-C / A, 0));
                return new double[] { 1, 0, -tmp.X };
            }
            PointD pt1 = Coordinate.XYToPxy(new PointD(0, -C / B)), pt2 = Coordinate.XYToPxy(new PointD(-C / A, 0));
            return pt1.GetABC(pt2);
        }
        public void BuildCircleSamples(Curve cur, Curve pCur, PointD center, double r)
        {
            BuildArcSamples(cur, pCur, center, r, 0, Core.Helper.Angle.RadRound);
        }
        public void BuildArcSamples(Curve cur, Curve pCur, PointD center, double r, double rStart, double rSweep)
        {
            if (cur == null && pCur == null) return;
            if (cur != null) cur.Clear();
            if (pCur != null) pCur.Clear();
            double prec = (rSweep >= 0 ? 1 : -1) / Settings.Instance.CircleAccuracy, stop = rStart + rSweep;
            for (double theta = rStart; rSweep >= 0 ? theta <= stop : theta >= stop; theta += prec)
            {
                PointD pt = r * Utility.GetUnitVector(theta) + center;
                if (cur != null) cur.Add(pt);
                if (pCur != null)
                {
                    if (Coordinate != null) pt = Coordinate.XYToPxy(pt);
                    if (pt.IsPaintable) pCur.Add(pt);
                }
            }
        }
        public double RadToPRad(double rad)
        {
            return Coordinate == null ? rad : Coordinate.RadToPRad(rad);
        }
        public double DegToPDeg(double deg)
        {
            return Coordinate == null ? deg : Coordinate.DegToPDeg(deg);
        }
        /// <summary>
        /// 若画板的角度单位为弧度，则返回弧度本身，否则返回弧度的角度制
        /// </summary>
        /// <param name="rad"></param>
        /// <returns></returns>
        public double ShowRad(double rad)
        {
            if (AngleUnit == AngleUnit.Radian) return rad;
            return rad * Core.Helper.Angle.RToD;
        }
        /// <summary>
        /// 若画板的角度单位为弧度，则返回弧度本身，否则返回角度的弧度制
        /// </summary>
        /// <param name="angle"></param>
        /// <returns></returns>
        public double GetRad(double angle)
        {
            if (AngleUnit == AngleUnit.Radian) return angle;
            return angle * Angle.DToR;
        }
        /// <summary>
        /// 若画板没有坐标系或有直角坐标系，则返回pt本身，否则返回pt的极坐标形式
        /// </summary>
        /// <param name="pt"></param>
        /// <returns></returns>
        public PointD ShowPoint(PointD pt)
        {
            if (CoordinateType == CoordinateSystemType.PolarCoordinate) return (Coordinate as PolarCoordinate).XYtoRT(pt);
            return pt;
        }
        public PointD XYToPxy(PointD XY)
        {
            return Coordinate == null ? XY : Coordinate.XYToPxy(XY);
        }
        public PointD PxyToXY(PointD Pxy)
        {
            return Coordinate == null ? Pxy : Coordinate.PxyToXY(Pxy);
        }
        public double kToPk(double k)
        {
            return Coordinate == null ? k : Coordinate.kToPk(k);
        }
        public double PkTok(double Pk)
        {
            return Coordinate == null ? Pk : Coordinate.PkTok(Pk);
        }
    }
}
